Git Product home page Git Product logo

zstring's Introduction

ZString

GitHub Actions Releases

Zero Allocation StringBuilder for .NET Core and Unity.

  • Struct StringBuilder to avoid allocation of builder itself
  • Rent write buffer from ThreadStatic or ArrayPool
  • All append methods are generics(Append<T>(T value)) and write to buffer directly instead of concatenate value.ToString
  • T1~T16 AppendFormat(AppendFormat<T1,...,T16>(string format, T1 arg1, ..., T16 arg16) avoids boxing of struct argument
  • Also T1~T16 Concat(Concat<T1,...,T16>(T1 arg1, ..., T16 arg16)) avoid boxing and value.ToString allocation
  • Convenient ZString.Format/Concat/Join methods can replace instead of String.Format/Concat/Join
  • Can build both Utf16(Span<char>) and Utf8(Span<byte>) directly
  • Can use inner buffer to avoid allocate final string
  • Integrated with Unity TextMeshPro to avoid string allocation

image

This graph compares following codes.

  • "x:" + x + " y:" + y + " z:" + z
  • ZString.Concat("x:", x, " y:", y, " z:", z)
  • string.Format("x:{0} y:{1} z:{2}", x, y, z)
  • ZString.Format("x:{0} y:{1} z:{2}", x, y, z)
  • new StringBuilder(), Append(), .ToString()
  • ZString.CreateStringBuilder(), Append(), .ToString()

"x:" + x + " y:" + y + " z:" + z is converted to String.Concat(new []{ "x:", x.ToString(), " y:", y.ToString(), " z:", z.ToString() }) by C# compiler. It has each .ToString allocation and params array allocation. string.Format calls String.Format(string, object, object, object) so each arguments causes int -> object boxing.

All ZString methods only allocate final string. Also, ZString has enabled to access inner buffer so if output target has stringless api(like Unity TextMeshPro's SetCharArray), you can achieve completely zero allocation.

The blog post of detailed explanation by author: medium@neuecc/ZString

Related project for loggin using with ZString, Cysharp/ZLogger - Zero Allocation Text/Strcutured Logger.

Table of Contents

Getting Started

For .NET Core, use NuGet.

PM> Install-Package ZString

For Unity, check the releases page, download ZString.Unity.unitypackage.

using Cysharp.Text; // namespace

async void Example(int x, int y, int z)
{
    // same as x + y + z
    _ = ZString.Concat(x, y, z);

    // also can use numeric format strings
    _ = ZString.Format("x:{0}, y:{1:000}, z:{2:P}",x, y, z);

    _ = ZString.Join(',', x, y, z);

    // for Unity, direct write(avoid string allocation completely) to TextMeshPro
    tmp.SetTextFormat("Position: {0}, {1}, {2}", x, y, z);

    // create StringBuilder
    using(var sb = ZString.CreateStringBuilder())
    {
        sb.Append("foo");
        sb.AppendLine(42);
        sb.AppendFormat("{0} {1:.###}", "bar", 123.456789);

        // and build final string
        var str = sb.ToString();

        // for Unity, direct write to TextMeshPro
        tmp.SetText(sb);

        // write to destination buffer
        sb.TryCopyTo(dest, out var written);
    }

    // prepare format, return value should store to field(like RegexOptions.Compile)
    var prepared = ZString.PrepareUtf16<int, int>("x:{0}, y:{1:000}");
    _ = prepared.Format(10, 20);

    // C# 8.0, Using declarations
    // create Utf8 StringBuilder that build Utf8 directly to avoid encoding
    using var sb2 = ZString.CreateUtf8StringBuilder();

    sb2.AppendFormat("foo:{0} bar:{1}", x, y);

    // directly write to steam or dest to avoid allocation
    await sb2.WriteToAsync(stream);
    sb2.CopyTo(bufferWritter);
    sb2.TryCopyTo(dest, out var written);
}

Reference

static class ZString

method returns description
CreateStringBuilder() Utf16ValueStringBuilder Create the Utf16 string StringBuilder.
CreateStringBuilder(bool notNested) Utf16ValueStringBuilder Create the Utf16 string StringBuilder, when true uses thread-static buffer that is faster but must return immediately.
CreateUtf8StringBuilder() Utf8ValueStringBuilder Create the Utf8(Span<byte>) StringBuilder.
CreateUtf8StringBuilder(bool notNested) Utf8ValueStringBuilder Create the Utf8(Span<byte>) StringBuilder, when true uses thread-static buffer that is faster but must return immediately.
Join(char/string, T[]/IE<T>) string Concatenates the elements of an array, using the specified seperator between each element.
PrepareUtf16<T1,..,T16>(string) Utf16PreparedFormat<T1,...,T16> Prepare string format to avoid parse template in each operation.
PrepareUtf8<T1,..,T16>(string) Utf8PreparedFormat<T1,...,T16> Prepare string format to avoid parse template in each operation.
Concat<T1,..,T16>(T1,..,T16) string Concatenates the string representation of some specified values.
Format<T1,..,T16>(string, T1,..,T16) string Replaces one or more format items in a string with the string representation of some specified values.
Utf8Format<T1,..,T16>(IBufferWriter<byte>, T1,..,T16) void Replaces one or more format items in a string with the string representation of some specified values.

struct Utf16ValueStringBuilder : IBufferWriter<char>, IDisposable

method returns description
Length int Length of written buffer.
AsSpan() ReadOnlySpan<char> Get the written buffer data.
AsMemory() ReadOnlyMemory<char> Get the written buffer data.
AsArraySegment() ArraySegment<char> Get the written buffer data.
Dispose() void Return the inner buffer to pool.
Append<T>(T value) void Appends the string representation of a specified value to this instance.
Append<T>(T value, string format) void Appends the string representation of a specified value to this instance with numeric format strings.
AppendJoin(char/string, T[]/IE<T>) void Concatenates and appends the elements of an array, using the specified seperator between each element.
AppendLine() void Appends the default line terminator to the end of this instance.
AppendLine<T>(T value) void Appends the string representation of a specified value followed by the default line terminator to the end of this instance.
AppendLine<T>(T value, string format) void Appends the string representation of a specified value with numeric format strings followed by the default line terminator to the end of this instance.
AppendFormat<T1,..,T16>(string, T1,..,T16) void Appends the string returned by processing a composite format string, each format item is replaced by the string representation of arguments.
TryCopyTo(Span<char>, out int) bool Copy inner buffer to the destination span.
ToString() string Converts the value of this instance to a System.String.
GetMemory(int sizeHint) Memory<char> IBufferWriter.GetMemory.
GetSpan(int sizeHint) Span<char> IBufferWriter.GetSpan.
Advance(int count) void IBufferWriter.Advance.
static RegisterTryFormat<T>(TryFormat<T>) void Register custom formatter.

struct Utf8ValueStringBuilder : IBufferWriter<byte>, IDisposable

method returns description
Length int Length of written buffer.
AsSpan() ReadOnlySpan<char> Get the written buffer data.
AsMemory() ReadOnlyMemory<char> Get the written buffer data.
AsArraySegment() ArraySegment<char> Get the written buffer data.
Dispose() void Return the inner buffer to pool.
Append<T>(T value) void Appends the string representation of a specified value to this instance.
Append<T>(T value, StandardFormat format) void Appends the string representation of a specified value to this instance with numeric format strings.
AppendJoin(char/string, T[]/IE<T>) void Concatenates and appends the elements of an array, using the specified seperator between each element.
AppendLine() void Appends the default line terminator to the end of this instance.
AppendLine<T>(T value) void Appends the string representation of a specified value followed by the default line terminator to the end of this instance.
AppendLine<T>(T value, StandardFormat format) void Appends the string representation of a specified value with numeric format strings followed by the default line terminator to the end of this instance.
AppendFormat<T1,..,T16>(string, T1,..,T16) void Appends the string returned by processing a composite format string, each format item is replaced by the string representation of arguments.
CopyTo(IBufferWriter<byte>) void Copy inner buffer to the buffer writer.
TryCopyTo(Span<byte>, out int) bool Copy inner buffer to the destination span.
WriteToAsync(Stream stream) Task Write inner buffer to stream.
ToString() string Encode the innner utf8 buffer to a System.String.
GetMemory(int sizeHint) Memory<char> IBufferWriter.GetMemory.
GetSpan(int sizeHint) Span<char> IBufferWriter.GetSpan.
Advance(int count) void IBufferWriter.Advance.
static RegisterTryFormat<T>(TryFormat<T>) void Register custom formatter.

class Utf16PreparedFormat<T1,..,T16>

method returns description
Format string Replaces one or more format items in a string with the string representation of some specified values.
FormatTo<TBufferWriter>(ref TBufferWriter, T1,..,T16) void Replaces one or more format items in a string with the string representation of some specified values.

class Utf8PreparedFormat<T1,..,T16>

method returns description
Format string Replaces one or more format items in a string with the string representation of some specified values.
FormatTo<TBufferWriter>(ref TBufferWriter, T1,..,T16) void Replaces one or more format items in a string with the string representation of some specified values.

class ZStringWriter : TextWriter

A TextWriter implementation that is backed with Utf16ValueStringBuilder
It's important to make sure the writer is always properly disposed.

static class TextMeshProExtensions(Unity only)

method returns description
SetText(Utf16ValueStringBuilder) void Set inner buffer to text mesh pro directly to avoid string allocation.
SetTextFormat<T1,..,T16>(string, T1,..,T16) void Set formatted string without string allocation.

Unity

Install via UPM git URL package or asset package(ZString...*.unitypackage) available in ZString/releases page.

  • https://github.com/Cysharp/ZString.git?path=src/ZString.Unity/Assets/Scripts/ZString

If you want to set a target version, ZString uses the *.*.* release tag so you can specify a version like #2.4.0. For example https://github.com/Cysharp/ZString.git?path=src/ZString.Unity/Assets/Scripts/ZString#2.4.0.

Supporting minimum Unity version is 2021.3. The dependency managed DLL System.Runtime.CompilerServices.Unsafe/6.0.0 is included with unitypackage. For git references, you will need to add them in another way as they are not included to avoid unnecessary dependencies; either extract the dll from unitypackage or download it from the NuGet page.

TextMeshPro support is automatically enabled when importing the com.unity.textmeshpro package from package manager. (If you do not use the package manager, define the scripting define symbol ZSTRING_TEXTMESHPRO_SUPPORT to enable it.)

Advanced Tips

ZString.CreateStringBuilder(notNested:true) is a special optimized parameter that uses ThreadStatic buffer instead of rent from ArrayPool. It is slightly faster but can not use in nested.

using(var sb = ZString.CreateStringBuilder(true))
{
    sb.Append("foo");

    using var sb2 = ZString.CreateStringBuilder(true); // NG, nested stringbuilder uses conflicted same buffer
    var str = ZString.Concat("x", 100); // NG, ZString.Concat/Join/Format uses threadstatic buffer
}
// OK, return buffer immediately.
using(var sb = ZString.CreateStringBuilder(true))
{
    sb.Append("foo");
    return sb.ToString();
}

ZString.CreateStringBuilder() is same as ZString.CreateStringBuilder(notNested:false).


In default, SByte, Int16, Int32, Int64, Byte, UInt16, UInt32, UInt64, Single, Double, TimeSpan, DateTime, DateTimeOffset, Decimal, Guid, String, Char are used there own formatter to avoid .ToString() allocation, write directly to buffer. If not exists there list type, used .ToString() and copy string data.

If you want to avoid to convert string in custom type, you can register your own formatter.

Utf16ValueStringBuilder.RegisterTryFormat((MyStruct value, Span<char> destination, out int charsWritten, ReadOnlySpan<char> format) =>
{
    // write value to destionation and set size to charsWritten.
    charsWritten = 0;
    return true;
});

Utf8ValueStringBuilder.RegisterTryFormat((MyStruct value, Span<byte> destination, out int written, StandardFormat format) =>
{
    written = 0;
    return true;
});

CreateStringBuilder and CreateUtf8StringBuilder must use with using. Because their builder rent 64K buffer from ArrayPool. If not return buffer, allocate 64K buffer when string builder is created.


Utf16ValueStringBuilder and Utf8ValueStringBuilder are mutable struct, be careful to copy by passing method. Use ref and try-finally.

void Build()
{
    var sb = ZString.CreateStringBuilder();
    try
    {
        BuildHeader(ref sb);
        BuildMessage(ref sb);
    }
    finally
    {
        // when use with `ref`, can not use `using`.
        sb.Dispose();
    }
}


void BuildHeader(ref Utf16ValueStringBuilder builder)
{
    //..
}

void BuildMessage(ref Utf16ValueStringBuilder builder)
{
    //..
}

Utf8Format, Utf8StringBuilder uses Utf8Formatter.TryFormat and there format string is not same as standard format. It uses StandardFormat, combinate of symbol char and precision. Supported format string symbol can find in Utf8Formatter.TryFormat document(For example Int32 supports G, D, N, X and Boolean supports G, I). Precision(zero padding) can pass after symbol like D2. For example sb.AppendFormat("{0:D2}:{1:D2}:{2:D2}", hour, minute, second).

TryFormat(DateTime) and TryFormat(TimeSpan) symbol is too restricted than standard string format. If you want to use custom format, deconstruct there Day, Hour, etc.


Utf8ValueStringBuilder and Utf16ValueStringBuilder implements IBufferWriter so you can pass serializer(such as JsonSerializer of System.Text.Json). But be careful to boxing copy, ValueStringBuilder is mutable struct. For example,

using var sb = ZString.CreateUtf8StringBuilder();
IBufferWriter<byte> boxed = sb;
var writer = new Utf8JsonWriter(boxed);
JsonSerializer.Serialize(writer, ....);

using var unboxed = (Utf8ValueStringBuilder)boxed;
var str = unboxed.ToString();

License

This library is licensed under the MIT License.

.NET Standard 2.0 and Unity version borrows dotnet/runtime conversion methods, there exists under ZString/Number directory. This third-party license follows runtime/LICENSE.TXT.

zstring's People

Contributors

brian6932 avatar daramkun avatar github-actions[bot] avatar guitarrapc avatar hadashia avatar itn3000 avatar kamyker avatar kochounoyume avatar lahma avatar lukasz-pyrzyk avatar mayuki avatar mdsitton avatar natsu1211 avatar neuecc avatar pcysl5edgo avatar piti6 avatar simoncropp avatar to11mtm avatar udaken avatar xin9le avatar yoshifumikawai avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

zstring's Issues

It looks like memory leak in Utf16ValueStringBuilder.Insert

Original buffer is not released before assigning new buffer

int remainLnegth = this.index - index;
buffer.AsSpan(index, remainLnegth).CopyTo(newBuffer.AsSpan(newBufferIndex));
buffer = newBuffer;
this.index = newBufferIndex + remainLnegth;
}

For example Grow releases buffer before assigning new one

buffer.CopyTo(newBuffer, 0);
if (buffer.Length != ThreadStaticBufferSize)
{
ArrayPool<char>.Shared.Return(buffer);
}
buffer = newBuffer;
}

ZString.Format with "Custom date and time format strings" | Unity

ZString:2.1.1
Unity:2018.4.17f1

There is a difference in output from string.Format.

TimeSpan span = new TimeSpan(12,34,56);
Debug.Log($"string.Format: {string.Format(@"{0:hh\:mm\:ss}", span)}");
Debug.Log($"ZString.Format: {ZString.Format(@"{0:hh\:mm\:ss}", span)}");
string.Format: 12:34:56
ZString.Format: 56

v2.5.1 compile error: BitOperations duplicate in System.Runtime

Error CS0433 : ็ฑปๅž‹โ€œBitOperationsโ€ๅŒๆ—ถๅญ˜ๅœจไบŽโ€œZString, Version=2.5.1.0, Culture=neutral, PublicKeyToken=df4c250b14d82627โ€ๅ’Œโ€œSystem.Runtime, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3aโ€ไธญ

About .NET 7.0 Support

Hello. I am currently developing an application using .NET 7.0 because of Native AOT.

While trying to optimize string garbage using ZString, it worked fine in the debug environment, but crashed when built with Native AOT.

After receiving the ZString source code and building it myself, I checked the warning message and it said that using Enum.GetValues() is not compatible with Native AOT.

I think you should use Enum.GetValuesAsUnderlyingType() (added in .NET 7.0) or just use ToString().

[Unity 2020.3] ZString's StringBuilder slower than System.StringBuilder?

When reviewing this wonderful StringBuilder replacement, I noticed the performance for Append() with string type is much worse compared to System.Text.StringBuilder.

image

The test code I'm using is:

int COUNT = 1000;
List<string> strings = new List<string>();
for (int i = 0; i < 100; i++)
	strings.Add("123456789");

Profiler.BeginSample("Append/SharedStringBuilderScope()");
{
	System.Text.StringBuilder sb = new System.Text.StringBuilder();
	for (int i = 0; i < COUNT; i++)
	{
		for (int j = 0; j < strings.Count; j++)
		{
			sb.Append(strings[j]);
		}

		sb.ToString();
		sb.Clear();
	}
}
Profiler.EndSample();

Profiler.BeginSample("Append/ZString.StringBuilder()");
for (int i = 0; i < COUNT; i++)
{
	using (var sb = ZString.CreateStringBuilder())
	{
		for (int j = 0; j < strings.Count; j++)
		{
			sb.Append(strings[j]);
		}

		sb.ToString();
	}
}
Profiler.EndSample();

Is this a known issue? Based on deep profiling in Unity, I noticed that the bottleneck was caused by explicit IntPtr casting. I'm not sure if this is just a bogus timing due to deep profiling, but making IL2CPP builds also shows it to be performing poorly vs System.Text.StringBuilder

ZString.Join with HttpStatusCode throws Exception

ZString 2.2.0

When I use ZString.Join with HttpStatusCode, it throws System.TypeInitializationException.

Normal enum or Flags enum passes unit test like below.

//pass
[Fact]
public void Test_ZStringJoin_Enum()
{
    var inputs = new[]
    {
        SearchOption.AllDirectories,
        SearchOption.TopDirectoryOnly,
    };

    var result = ZString.Join(" or ", inputs);

    result.ShouldBe($"{nameof(SearchOption.AllDirectories)} or {nameof(SearchOption.TopDirectoryOnly)}");
}

//pass
[Fact]
public void Test_ZStringJoin_FlagsEnum()
{
    var inputs = new[]
    {
        FileOptions.None,
        FileOptions.RandomAccess,
    };

    var result = ZString.Join(" or ", inputs);

    result.ShouldBe($"{nameof(FileOptions.None)} or {nameof(FileOptions.RandomAccess)}");
}

But when I use HttpStatusCode, it throws Exception.

//FAIL!!
[Fact]
public void Test_ZStringJoin_HttpStatusCode()
{
    var inputs = new[]
    {
        HttpStatusCode.OK,
        HttpStatusCode.Created,
    };

    var result = ZString.Join(" or ", inputs);

    result.ShouldBe($"{nameof(HttpStatusCode.OK)} or {nameof(HttpStatusCode.Created)}");
}

/*
System.TypeInitializationException : The type initializer for 'Cysharp.Text.EnumUtil`1' threw an exception.
  ---- System.ArgumentException : An item with the same key has already been added. Key: Ambiguous
StackTrace: 
  EnumUtil`1.TryFormatUtf16(T value, Span`1 dest, Int32& written, ReadOnlySpan`1 _)
  Utf16ValueStringBuilder.Append[T](T value)
  Utf16ValueStringBuilder.AppendJoinInternal[T](ReadOnlySpan`1 separator, ReadOnlySpan`1 values)
  ZString.JoinInternal[T](ReadOnlySpan`1 separator, ReadOnlySpan`1 values)
  ZString.Join[T](String separator, T[] values)
  UnitTest1.Test_ZStringJoin_HttpStatusCode()
  ----- Inner Stack Trace -----
  Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
  Dictionary`2.Add(TKey key, TValue value)
  EnumUtil`1.cctor()
*/

I think the main cause is Enum.GetValues(typeof(HttpStatusCode)) returns the same value like MultipleChoices, and use them as the key of Dictionary in EnumUtil's constructor.
Maybe need to key existence check?

Thanks.

Add assembly signing

Would it be possible to add assembly signing to build process and published DLL (with public snk file). Now this library cannot be referenced from signed assemblies. I believe Microsoft recommendation is to sign assemblies with publicly available key for compatibility and not security.

.Append(string) does not work when ZString is created as a readonly class member

I am experimenting with substituting StringBuilder with ZString. In my particular case, when I attempt to use .Append, it does not append the string (in the debugger, I can see that .Length stays 0). This is the minimal repro code:

class Program
{
    static void Main() => new Program().Test();

    void Test()
    {
        string sigil = "\u001B[38;5;178m@";

        // StringBuilder
        sb.Append(sigil);
        Console.WriteLine(sb.ToString()); // Prints '@' in yellow

        // ZString
        zs.Append(sigil);
        Console.WriteLine(zs.ToString()); // Does not print anything
    }

    private readonly Cysharp.Text.Utf16ValueStringBuilder zs = Cysharp.Text.ZString.CreateStringBuilder();
    private readonly System.Text.StringBuilder sb = new();
}

Compiler error when importing via UPM

When I import ZString with the following minimal manifest.json...

{
  "scopedRegistries": [
    {
      "name": "package.openupm.com",
      "url": "https://package.openupm.com",
      "scopes": [
        "com.cysharp.zstring"
      ]
    }
  ],
  "dependencies": {
    "com.cysharp.zstring": "2.3.1",
    "com.unity.2d.animation": "5.0.3",
    "com.unity.2d.pixel-perfect": "4.0.1",
    "com.unity.2d.psdimporter": "4.0.2",
    "com.unity.2d.sprite": "1.0.0",
    "com.unity.2d.spriteshape": "5.1.0",
    "com.unity.2d.tilemap": "1.0.0",
    "com.unity.collab-proxy": "1.3.9",
    "com.unity.ide.rider": "2.0.7",
    "com.unity.ide.visualstudio": "2.0.5",
    "com.unity.ide.vscode": "1.2.3",
    "com.unity.test-framework": "1.1.19",
    "com.unity.textmeshpro": "3.0.1",
    "com.unity.timeline": "1.4.4",
    "com.unity.ugui": "1.0.0",
    "com.unity.modules.ai": "1.0.0",
    "com.unity.modules.androidjni": "1.0.0",
    "com.unity.modules.animation": "1.0.0",
    "com.unity.modules.assetbundle": "1.0.0",
    "com.unity.modules.audio": "1.0.0",
    "com.unity.modules.cloth": "1.0.0",
    "com.unity.modules.director": "1.0.0",
    "com.unity.modules.imageconversion": "1.0.0",
    "com.unity.modules.imgui": "1.0.0",
    "com.unity.modules.jsonserialize": "1.0.0",
    "com.unity.modules.particlesystem": "1.0.0",
    "com.unity.modules.physics": "1.0.0",
    "com.unity.modules.physics2d": "1.0.0",
    "com.unity.modules.screencapture": "1.0.0",
    "com.unity.modules.terrain": "1.0.0",
    "com.unity.modules.terrainphysics": "1.0.0",
    "com.unity.modules.tilemap": "1.0.0",
    "com.unity.modules.ui": "1.0.0",
    "com.unity.modules.uielements": "1.0.0",
    "com.unity.modules.umbra": "1.0.0",
    "com.unity.modules.unityanalytics": "1.0.0",
    "com.unity.modules.unitywebrequest": "1.0.0",
    "com.unity.modules.unitywebrequestassetbundle": "1.0.0",
    "com.unity.modules.unitywebrequestaudio": "1.0.0",
    "com.unity.modules.unitywebrequesttexture": "1.0.0",
    "com.unity.modules.unitywebrequestwww": "1.0.0",
    "com.unity.modules.vehicles": "1.0.0",
    "com.unity.modules.video": "1.0.0",
    "com.unity.modules.vr": "1.0.0",
    "com.unity.modules.wind": "1.0.0",
    "com.unity.modules.xr": "1.0.0"
  }
}

...I get this set of compiler errors:

Library\PackageCache\[email protected]\EnumUtil.cs(37,52): error CS0246: The type or namespace name 'Span<>' could not be found (are you missing a using directive or an assembly reference?)

Library\PackageCache\[email protected]\EnumUtil.cs(37,86): error CS0246: The type or namespace name 'ReadOnlySpan<>' could not be found (are you missing a using directive or an assembly reference?)

Library\PackageCache\[email protected]\EnumUtil.cs(48,51): error CS0246: The type or namespace name 'Span<>' could not be found (are you missing a using directive or an assembly reference?)

Library\PackageCache\[email protected]\EnumUtil.cs(48,85): error CS0246: The type or namespace name 'StandardFormat' could not be found (are you missing a using directive or an assembly reference?)

Library\PackageCache\[email protected]\Number\BitOperations.cs(23,24): error CS0246: The type or namespace name 'ReadOnlySpan<>' could not be found (are you missing a using directive or an assembly reference?)

Library\PackageCache\[email protected]\Number\BitOperations.cs(31,24): error CS0246: The type or namespace name 'ReadOnlySpan<>' could not be found (are you missing a using directive or an assembly reference?)

Library\PackageCache\[email protected]\FastNumberWriter.cs(11,42): error CS0246: The type or namespace name 'Span<>' could not be found (are you missing a using directive or an assembly reference?)

Library\PackageCache\[email protected]\FastNumberWriter.cs(173,43): error CS0246: The type or namespace name 'Span<>' could not be found (are you missing a using directive or an assembly reference?)

Library\PackageCache\[email protected]\FormatHelper.cs(13,95): error CS0246: The type or namespace name 'ReadOnlySpan<>' could not be found (are you missing a using directive or an assembly reference?)

Library\PackageCache\[email protected]\FormatHelper.cs(45,108): error CS0246: The type or namespace name 'ReadOnlySpan<>' could not be found (are you missing a using directive or an assembly reference?)

Library\PackageCache\[email protected]\IResettableBufferWriter.cs(8,51): error CS0246: The type or namespace name 'IBufferWriter<>' could not be found (are you missing a using directive or an assembly reference?)

Library\PackageCache\[email protected]\FormatHelper.cs(14,35): error CS0246: The type or namespace name 'IBufferWriter<>' could not be found (are you missing a using directive or an assembly reference?)

Library\PackageCache\[email protected]\FormatHelper.cs(46,35): error CS0246: The type or namespace name 'IBufferWriter<>' could not be found (are you missing a using directive or an assembly reference?)

Library\PackageCache\[email protected]\PreparedFormat.cs(255,35): error CS0246: The type or namespace name 'IBufferWriter<>' could not be found (are you missing a using directive or an assembly reference?)

Library\PackageCache\[email protected]\PreparedFormat.cs(45,35): error CS0246: The type or namespace name 'IBufferWriter<>' could not be found (are you missing a using directive or an assembly reference?)

There are many similar compiler errors as well. This occurs on Unity 2020.2.1f1 on Windows 10.

Unittest failed

Unittest failed

I ran the unit tests on my local mac and found 2 errors

image image

My enviroment:

> dotnet --info
.NET SDK:
 Version:   7.0.404
 Commit:    22f221a24c

่ฟ่กŒๆ—ถ็Žฏๅขƒ:
 OS Name:     Mac OS X
 OS Version:  14.1
 OS Platform: Darwin
 RID:         osx-arm64
 Base Path:   /usr/local/share/dotnet/sdk/7.0.404/

Host:
  Version:      7.0.14
  Architecture: arm64
  Commit:       808851b07a

Compilation errors

I grabbed 2.4.2 and I get a slew of compilation errors on Unity 2020.3.29 like

Library\PackageCache\com.cysharp.zstring@044a79a\IResettableBufferWriter.cs(8,51): error CS0246: The type or namespace name 'IBufferWriter<>' could not be found (are you missing a using directive or an assembly reference?)

Library\PackageCache\com.cysharp.zstring@044a79a\Number\BitOperations.cs(23,24): error CS0246: The type or namespace name 'ReadOnlySpan<>' could not be found (are you missing a using directive or an assembly reference?)

NullReferenceException

I have code that is working in 'Debug' builds but crashing in 'Release' builds. The debugger told me it crashed on the line below where I create the string builder, StackTrace didn't provide any additional. I'm compiling against .NET 5.

Any ideas on why this might be occuring?

Code

using var sb = ZString.CreateStringBuilder();

Exception

System.NullReferenceException: Object reference not set to an instance of an object.

image

image

May be wrong Custom date and time format strings | Unity

ZString:2.1.1
Unity:2018.4.17f1

TimeSpan span = new TimeSpan(12,34,56);
Debug.Log($"string.Format: {string.Format(@"{0:hh\:mm\:ss}", span)}");
Debug.Log($"ZString.Format: {ZString.Format(@"{0:hh\:mm\:ss}", span)}");
string.Format: 12:34:56
ZString.Format: 56

Utf8JsonWriter

Hello, can you tell me whether the Utf8JsonWriter mentioned in the document exists.

ZString.Join() on List<string> returns unexpectedly

// Wroks!
var jsons = payloads.Select(payload => _jsonLibrary.ToJson(payload));
return ZString.Join(Environment.NewLine, jsons); 
// Wroks!
var jsons = payloads.Select(payload => _jsonLibrary.ToJson(payload)).ToArray();
return ZString.Join(Environment.NewLine, jsons); 
// Wrong
var jsons = payloads.Select(payload => _jsonLibrary.ToJson(payload)).ToList();
return ZString.Join(Environment.NewLine, jsons); 
// Works
var jsons = payloads.Select(payload => _jsonLibrary.ToJson(payload)).ToList().AsEnumerable();
return ZString.Join(Environment.NewLine, jsons); 

Expected Returns: JsonLine (Json Objects delimited by NewLine)
Actual Returns: System.Collections.Generic.List`1[System.String]

FormatHelper.cs has no meta file, but it's in an immutable folder.

Hello,
I've installed ZString with openupm-cli on my project.

Unfortunately, I'm stuck with an error message stating
Asset Packages/com.cysharp.zstring/FormatHelper.cs has no meta file, but it's in an immutable folder. The asset will be ignored.
with 410+ errors

As a workaround,
if I manually generate .meta file by copying to other directory, then putting it back, it temporarly works until the next module refresh; the .meta file disappears.

I'm using Unity 2019.4.18 LTS.
Thanks in advance.

ZString.Join is looklike bad

see this benchmark.ZString.Join is more slow and no power in memory?

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19043.1766 (21H1/May2021Update)
AMD Ryzen 9 5900X, 1 CPU, 24 logical and 12 physical cores
.NET SDK=6.0.300
  [Host]               : .NET 6.0.5 (6.0.522.21309), X64 RyuJIT
  .NET 6.0             : .NET 6.0.5 (6.0.522.21309), X64 RyuJIT
  .NET Framework 4.6.1 : .NET Framework 4.8 (4.8.4515.0), X64 RyuJIT

Method Job Runtime Source Mean Error StdDev Ratio RatioSD Gen 0 Allocated
StringJoin .NET 6.0 .NET 6.0 String[3] 17.68 ns 0.241 ns 0.226 ns 1.00 0.00 0.0019 32 B
ZStringJoin .NET 6.0 .NET 6.0 String[3] 44.23 ns 0.466 ns 0.436 ns 2.50 0.03 0.0019 32 B
StringJoin .NET 6.0 .NET 6.0 String[5] 24.33 ns 0.121 ns 0.113 ns 1.38 0.02 0.0024 40 B
ZStringJoin .NET 6.0 .NET 6.0 String[5] 57.08 ns 0.255 ns 0.226 ns 3.23 0.04 0.0024 40 B
StringJoin .NET Framework 4.6.1 .NET Framework 4.6.1 String[3] 34.09 ns 0.062 ns 0.058 ns 1.00 0.00 0.0063 40 B
ZStringJoin .NET Framework 4.6.1 .NET Framework 4.6.1 String[3] 167.40 ns 0.406 ns 0.360 ns 4.91 0.01 0.0062 40 B
StringJoin .NET Framework 4.6.1 .NET Framework 4.6.1 String[5] 51.88 ns 0.044 ns 0.034 ns 1.52 0.00 0.0076 48 B
ZStringJoin .NET Framework 4.6.1 .NET Framework 4.6.1 String[5] 203.03 ns 0.318 ns 0.297 ns 5.96 0.01 0.0076 48 B

Can u change your current stringbuilder.tostring to ------> (see in the description box)

public override string ToString()
      {
         return string.Create(buffer.Length, buffer,
            (x, y) =>
            {
               y.AsSpan(0, x.Length).CopyTo(x);
            }
         );
      }

i have read several times that the new string.Create(..) is much faster since it does only 1 internal allocation when u know the exact size of the buffer u wanna create a string of, and you do ! and there are ofc also no extra delegate allocation in this when u avouid using the 2.parameter "state" and use the (x, y) only! which I do in this case.

Naming conflict with TextMeshPro and their Extensions

Mac os 13.4 Test("{0,-20} {1,5:F}", "Adam", decimal 40);

Mac os 13.4
Test("{0,-20} {1,5:F}", "Adam", decimal 40);

Xunit.Sdk.XunitException: Expected actual to be
"Adam 40.000" with a length of 27, but
"Adam 40.00" has a length of 26, differs near "0" (index 25).
at FluentAssertions.Execution.XUnit2TestFramework.Throw(String message)
at FluentAssertions.Execution.TestFrameworkProvider.Throw(String message)
at FluentAssertions.Execution.DefaultAssertionStrategy.HandleFailure(String message)
at FluentAssertions.Execution.AssertionScope.FailWith(Func1 failReasonFunc) at FluentAssertions.Execution.AssertionScope.FailWith(Func1 failReasonFunc)
at FluentAssertions.Primitives.StringEqualityValidator.ValidateAgainstLengthDifferences()
at FluentAssertions.Primitives.StringValidator.Validate()
at FluentAssertions.Primitives.StringAssertions.Be(String expected, String because, Object[] becauseArgs)
at ZStringTests.FormatTest.Test[T0,T1](Boolean testUtf8, String format, T0 t0, T1 t1) in /Users/ruibinzhao/Downloads/ZString-master/tests/ZString.Tests/FormatTest.cs:line 31
at ZStringTests.FormatTest.Test[T0,T1](String format, T0 t0, T1 t1) in /Users/ruibinzhao/Downloads/ZString-master/tests/ZString.Tests/FormatTest.cs:line 15
at ZStringTests.CompositeFormatTest.AlignmentComponent() in /Users/ruibinzhao/Downloads/ZString-master/tests/ZString.Tests/CompositeFormatTest.cs:line 106
at ConsoleApp.Program.Run() in /Users/ruibinzhao/Downloads/ZString-master/sandbox/ConsoleApp/Program.cs:line 32
at ConsoleApp.Program.Main(String[] args) in /Users/ruibinzhao/Downloads/ZString-master/sandbox/ConsoleApp/Program.cs:line 23

Huge amounts of GC when appending floats

image
Here's a profiler image of the issue. We are essentially just appending floating point numbers (part of a vector) - we're using unity 2022.3.11f1

is this expected behaviour? is there any way to avoid this?

Built-in support for TextWriter implementations

Currently you cannot directly use StringWriter with ZString as StringWriter accepts regular StringBuilder. I created helper ZStringWriter for Orchard Core. Would it make sense to offer ZStringWriter (UTF-16) and Utf8ZStringWriter out of the box?

If you think it's a viable option I could offer a PR, just tell me desired names for the classes and namespace.

Still have GC??

I ran the example and saw the profile show. there is gc in every frame!

image
image

I don't know if i use it correctly.

Unity Version: 2020.3.22
ZString Version: 2.4.4

Any planned support for a Format() that takes a param array?

Hi, Right now we have helper functions that look like this:

void Log(string fmt, params object[] p) { log(string.Format(fmt,p); }

We can't replace string.Format() with ZString.Format() because it lacks a signature that takes a params array. Are there plans for that pls?

Is the content of LICENSE correct?

The ZString contains some files that are copyrighted by the .NET Foundation. Like this files.

However, the LICENSE file does not mention this.

Is this the state of affairs assumed by the repository owner?

OpenUPM

Is it reasonable to expect the package be available for unity through OpenUPM?

Infinite loop in ZString.Format

Overview

Infinite loop and memory allocation error in ZString.Format<string>()

Steps to reproduce

  1. create console app and add project ref to ZString
  2. run ZString.Format("abcdef: {0}", "abc");

Expected result

get "abcdef: abc"

Actual result

added "adef: " in loop in Utf16ValueStringBuilder.AppendFormat<T0> infinitely, and thrown OutOfMemoryException in ArrayPool<T>.Rent() finally.

Workaround for nested ZString.Format calls

Hi, let's say we have a class named Teammember that has this overridden ToString() code:
public override string ToString() { return ZString.Format("{0}:{1}:{2}",m_currentTeam,m_currentHealth,m_currentStamina);
but m_currentTeam is itself an instance of class Team with its own overridden ToString()
public override string ToString() { return ZString.Format("{0}:{1}:{2}",m_name,m_score,m_members);
If we call Teammember.ToString(), it'll end up calling ZString.Format recursively and cause an exception:
NestedStringBuilderCreationException: A nested call with notNested: true, or Either You forgot to call Utf16ValueStringBuilder.Dispose() of in the past.
because there's no way to control the nesting behavior of the StringBuilder that ZString.Format uses internally.

We'd like to continue to be able to override ToString(), so has anyone come up with a clean pattern to use ZString and nested ToString() calls? The other way we can do it is to create the StringBuilder instance manually and call Append/AppendFormat but it would require making a lot of changes to our codebase.

ZString.Join is slower than String.Join

ZString.Join is slower than String.Join when combining a list of String elements.
I think that a list with String as an element needs improvement because it is used in many workloads.


Below is the benchmark code.

using BenchmarkDotNet.Attributes;
using Cysharp.Text;
using System;
using System.Collections.Generic;
using System.Linq;
namespace PerfBenchmark.Benchmarks
{
    [Config(typeof(BenchmarkConfig))]
    public class StringListJoinBenchmark
    {
        //private const char Separator = ',';
        private const string Separator = ",";

        List<string> _emptyList;
        IEnumerable<string> _enum1;
        string[] _array1;
        List<string> _list1;
        IEnumerable<string> _enum2;
        string[] _array2;
        List<string> _list2;
        IEnumerable<string> _enum10;
        List<string> _list10;
        string[] _array10;

        public StringListJoinBenchmark()
        {
            _emptyList = new List<string>();
            _enum1 = Enumerable.Repeat(Guid.NewGuid().ToString(), 1);
            _list1 = _enum1.ToList();
            _array1 = _enum1.ToArray();
            _enum2 = Enumerable.Repeat(Guid.NewGuid().ToString(), 2);
            _list2 = _enum2.ToList();
            _array2 = _enum2.ToArray();
            _enum10 = Enumerable.Repeat(Guid.NewGuid().ToString(), 10);
            _list10 = _enum10.ToList();
            _array10 = _enum10.ToArray();
        }

        [Benchmark]
        public string JoinEmptyList() => String.Join(Separator, _emptyList);

        [Benchmark]
        public string ZJoinEmptyList() => ZString.Join(Separator, _emptyList);

        [Benchmark]
        public string JoinList1() => String.Join(Separator, _list1);

        [Benchmark]
        public string ZJoinList1() => ZString.Join(Separator, _list1);

        [Benchmark]
        public string JoinArray1() => String.Join(Separator, _array1);

        [Benchmark]
        public string ZJoinArray1() => ZString.Join(Separator, _array1);

        [Benchmark]
        public string JoinEnumerable1() => String.Join(Separator, _enum1);

        [Benchmark]
        public string ZJoinEnumerable1() => ZString.Join(Separator, _enum1);

        [Benchmark]
        public string JoinList2() => String.Join(Separator, _list2);

        [Benchmark]
        public string ZJoinList2() => ZString.Join(Separator, _list2);

        [Benchmark]
        public string JoinArray2() => String.Join(Separator, _array2);

        [Benchmark]
        public string ZJoinArray2() => ZString.Join(Separator, _array2);

        [Benchmark]
        public string JoinEnumerable2() => String.Join(Separator, _enum2);

        [Benchmark]
        public string ZJoinEnumerable2() => ZString.Join(Separator, _enum2);

        [Benchmark]
        public string JoinList10() => String.Join(Separator, _list10);

        [Benchmark]
        public string ZJoinList10() => ZString.Join(Separator, _list10);

        [Benchmark]
        public string JoinArray10() => String.Join(Separator, _array10);

        [Benchmark]
        public string ZJoinArray10() => ZString.Join(Separator, _array10);

        [Benchmark]
        public string JoinEnumerable10() => String.Join(Separator, _enum10);

        [Benchmark]
        public string ZJoinEnumerable10() => ZString.Join(Separator, _enum10);

    }
}

The following is the result of the execution. (.NET framework has a similar result.)

BenchmarkDotNet=v0.12.0, OS=Windows 10.0.19041
AMD Ryzen 7 3700X, 1 CPU, 16 logical and 8 physical cores
.NET Core SDK=3.1.400-preview-015151
  [Host]   : .NET Core 3.1.5 (CoreCLR 4.700.20.26901, CoreFX 4.700.20.27001), X64 RyuJIT
  ShortRun : .NET Core 3.1.5 (CoreCLR 4.700.20.26901, CoreFX 4.700.20.27001), X64 RyuJIT

Job=ShortRun  IterationCount=1  LaunchCount=1  
WarmupCount=1  
Method Mean Error Gen 0 Gen 1 Gen 2 Allocated
JoinEmptyList 19.697 ns NA 0.0048 - - 40 B
ZJoinEmptyList 11.102 ns NA - - - -
JoinList1 29.702 ns NA 0.0048 - - 40 B
ZJoinList1 51.796 ns NA 0.0114 - - 96 B
JoinArray1 3.841 ns NA - - - -
ZJoinArray1 51.001 ns NA 0.0114 - - 96 B
JoinEnumerable1 23.128 ns NA 0.0048 - - 40 B
ZJoinEnumerable1 81.611 ns NA 0.0162 - - 136 B
JoinList2 93.200 ns NA 0.0248 - - 208 B
ZJoinList2 97.387 ns NA 0.0200 - - 168 B
JoinArray2 25.569 ns NA 0.0201 - - 168 B
ZJoinArray2 92.378 ns NA 0.0200 - - 168 B
JoinEnumerable2 77.429 ns NA 0.0248 - - 208 B
ZJoinEnumerable2 128.068 ns NA 0.0248 - - 208 B
JoinList10 526.850 ns NA 0.2842 0.0019 - 2384 B
ZJoinList10 400.351 ns NA 0.0906 - - 760 B
JoinArray10 97.722 ns NA 0.0908 0.0002 - 760 B
ZJoinArray10 411.841 ns NA 0.0906 - - 760 B
JoinEnumerable10 426.296 ns NA 0.2847 0.0024 - 2384 B
ZJoinEnumerable10 483.942 ns NA 0.0954 - - 800 B

Are there any precautions when repeating the passing method?

Is it ok to use the following code when repeating the passing method?

void Build()
{
    var sb = ZString.CreateStringBuilder();
    try
    {
        BuildHeader(ref sb);
        BuildMessage(ref sb);
    }
    finally
    {
        sb.Dispose();
    }
}

void BuildHeader(ref Utf16ValueStringBuilder builder)
{
    //..
}

void BuildMessage(ref Utf16ValueStringBuilder builder)
{
    BuildName(ref sb);
    BuildContent(ref sb);
}

void BuildName(ref Utf16ValueStringBuilder builder)
{
    //..
}

void BuildContent(ref Utf16ValueStringBuilder builder)
{
    //..
}

Create Interface for shared methods

Hi,

I'd like to give this library a go. However, my implementation has scenarios for both utf8 and utf16 and the implementation the receives the ZStringBuilder doesn't necessarily care about that.
Because of that I'd like to accept an IStringBuilder to which I can pass both Utf8ValueStringBuilder and Utf16ValueStringBuilder.

AppendFormat based on ReadOnlySpan?

Hi I have a feature request, it would be nice to have the ability to have an implementation of AppendFormat that takes a ReadOnlySpan instead of the format string that way we can pass in data from another ZStringBuilder through span as a format string.

This is useful for building a format string based on input data coming in through a function without allocating a new string for the format string.

How does this compare to MikePopoloski/StringFormatter?

I was using StringBuilder, and just converted to using this:
MikePopoloski/StringFormatter

The project is dead, but it does work. I had to jiggle a few things to fully match the same AIP as StringBuilder, but now it does. Someone has added to it (and i have pulled it in) custom format specifiers for numbers, which might have some implementation issues, not sure on that yet.

So..

  1. Is anyone even aware of MikePopoloski/StringFormatter or by looking at it say what the likely comparison is to there?
  2. How well does this project here work as a 'drop in' StringBuilder replacement?

Unity 2021.2.0b6 breaks ZString because of System.Memory

Unity updated its framework and now it has System.Memory, but it is not as recent.
So it doesn't have all features, and we can no longer use System.Memory.dll because it will conflict with mscorlib.

For example, using the .NET framework profile (not .NET standard):

ZString\FormatParser.cs(34,28): error CS0570: 'ReadOnlySpan<T>.this[int].get' is not supported by the language
ZString\Shims.cs(51,32): error CS0570: 'ReadOnlySpan<T>.GetPinnableReference()' is not supported by the language

Unity IL2CPP backend seems not to be supported when Managed Stripping Level set to High

Due to Managed Stripping Level set to high - Unity could not resolve assembly "netstandard".
I am not sure whether this problem caused by Unity or by you.

Stacktrace:
Unhandled Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> Mono.Cecil.AssemblyResolutionException: Failed to resolve assembly: 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
at Unity.IL2CPP.Common.AssemblyResolver.ResolveInternal(AssemblyNameReference name)
at Unity.IL2CPP.Common.AssemblyResolver.Resolve(AssemblyNameReference name)
at Unity.IL2CPP.Common.WindowsRuntimeAwareMetadataResolver.Resolve(TypeReference type)
at Mono.Cecil.TypeReference.Resolve()
at Mono.Cecil.Mixin.CheckedResolve(TypeReference self)
at Mono.Cecil.SignatureReader.ReadCustomAttributeEnum(TypeReference enum_type)
at Mono.Cecil.SignatureReader.ReadCustomAttributeElement(TypeReference type)
at Mono.Cecil.SignatureReader.ReadCustomAttributeNamedArgument(Collection1& fields, Collection1& properties)
at Mono.Cecil.SignatureReader.ReadCustomAttributeNamedArguments(UInt16 count, Collection1& fields, Collection1& properties)
at Mono.Cecil.CustomAttribute.b__35_0(CustomAttribute attribute, MetadataReader reader)
at Mono.Cecil.ModuleDefinition.Read[TItem,TRet](TItem item, Func`3 read)
at Mono.Cecil.CustomAttribute.get_ConstructorArguments()
at Unity.Cecil.Visitor.Visitor.Visit(CustomAttribute customAttribute, Context context)
at Unity.Cecil.Visitor.Visitor.Visit(MethodDefinition methodDefinition, Context context)
at Unity.IL2CPP.GenericsCollection.GenericContextFreeVisitor.Visit(MethodDefinition methodDefinition, Context context)
at Unity.Cecil.Visitor.Visitor.Visit(TypeDefinition typeDefinition, Context context)
at Unity.Cecil.Visitor.Visitor.Visit(ModuleDefinition moduleDefinition, Context context)
at Unity.Cecil.Visitor.Visitor.Visit(AssemblyDefinition assemblyDefinition, Context context)

ZString.Join() not thread safe?

It seems that concurrent calling of ZString.Join() Fails.

Call stacks:

System.ArgumentException: Can't format argument. (Parameter 'value')
at Cysharp.Text.Utf8ValueStringBuilder.ThrowArgumentException(String paramName)
at Cysharp.Text.Utf8ValueStringBuilder.Append[T](T value)
at Cysharp.Text.ZString.Join[T](String separator, T[] values)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.