Skip to content

Commit b3db323

Browse files
update/text
Updated the Core/Text implementation to include more constructors, better documentation, and fewer allocations.
1 parent 9a909d5 commit b3db323

35 files changed

+431
-831
lines changed

OnixLabs.Core/Text/Base16.Convertible.cs

Lines changed: 12 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -14,66 +14,32 @@
1414

1515
using System;
1616
using System.Buffers;
17-
using System.Text;
1817

1918
namespace OnixLabs.Core.Text;
2019

2120
public readonly partial struct Base16
2221
{
23-
/// <summary>
24-
/// Gets the underlying <see cref="byte"/> array representation of the current <see cref="Base16"/> instance as a new <see cref="ReadOnlyMemory{T}"/> instance.
25-
/// </summary>
26-
/// <returns>Return the underlying <see cref="byte"/> array representation of the current <see cref="Base16"/> instance as a new <see cref="ReadOnlyMemory{T}"/> instance.</returns>
22+
/// <inheritdoc/>
2723
public ReadOnlyMemory<byte> AsReadOnlyMemory() => value;
2824

29-
/// <summary>
30-
/// Gets the underlying <see cref="byte"/> array representation of the current <see cref="Base16"/> instance as a new <see cref="ReadOnlySpan{T}"/> instance.
31-
/// </summary>
32-
/// <returns>Return the underlying <see cref="byte"/> array representation of the current <see cref="Base16"/> instance as a new <see cref="ReadOnlySpan{T}"/> instance.</returns>
25+
/// <inheritdoc/>
3326
public ReadOnlySpan<byte> AsReadOnlySpan() => value;
3427

35-
/// <summary>
36-
/// Create a new <see cref="Base16"/> instance from the specified <see cref="byte"/> array.
37-
/// </summary>
38-
/// <param name="value">The value from which to create a new <see cref="Base16"/> instance.</param>
39-
/// <returns>Returns a new <see cref="Base16"/> instance from the specified <see cref="byte"/> array.</returns>
40-
public static implicit operator Base16(byte[] value) => new(value);
41-
42-
/// <summary>
43-
/// Create a new <see cref="Base16"/> instance from the specified <see cref="ReadOnlySpan{T}"/> value.
44-
/// </summary>
45-
/// <param name="value">The value from which to create a new <see cref="Base16"/> instance.</param>
46-
/// <returns>Returns a new <see cref="Base16"/> instance from the specified <see cref="ReadOnlySpan{T}"/> value.</returns>
28+
/// <inheritdoc/>
4729
public static implicit operator Base16(ReadOnlySpan<byte> value) => new(value);
4830

49-
/// <summary>
50-
/// Create a new <see cref="Base16"/> instance from the specified <see cref="ReadOnlySequence{T}"/> value.
51-
/// </summary>
52-
/// <param name="value">The value from which to create a new <see cref="Base16"/> instance.</param>
53-
/// <returns>Returns a new <see cref="Base16"/> instance from the specified <see cref="ReadOnlySequence{T}"/> value.</returns>
31+
/// <inheritdoc/>
32+
public static implicit operator Base16(ReadOnlyMemory<byte> value) => new(value);
33+
34+
/// <inheritdoc/>
5435
public static implicit operator Base16(ReadOnlySequence<byte> value) => new(value);
5536

56-
/// <summary>
57-
/// Create a new <see cref="Base16"/> instance from the specified <see cref="string"/> value.
58-
/// <remarks>The <see cref="string"/> value will be encoded using the <see cref="Encoding.UTF8"/> encoding.</remarks>
59-
/// </summary>
60-
/// <param name="value">The value from which to create a new <see cref="Base16"/> instance.</param>
61-
/// <returns>Returns a new <see cref="Base16"/> instance from the specified <see cref="string"/> value.</returns>
62-
public static implicit operator Base16(string value) => new(value);
37+
/// <inheritdoc/>
38+
public static implicit operator Base16(ReadOnlySpan<char> value) => new(value);
6339

64-
/// <summary>
65-
/// Create a new <see cref="Base16"/> instance from the specified <see cref="char"/> array.
66-
/// <remarks>The <see cref="char"/> array will be encoded using the <see cref="Encoding.UTF8"/> encoding.</remarks>
67-
/// </summary>
68-
/// <param name="value">The value from which to create a new <see cref="Base16"/> instance.</param>
69-
/// <returns>Returns a new <see cref="Base16"/> instance from the specified <see cref="char"/> array.</returns>
70-
public static implicit operator Base16(char[] value) => new(value);
40+
/// <inheritdoc/>
41+
public static implicit operator Base16(ReadOnlyMemory<char> value) => new(value);
7142

72-
/// <summary>
73-
/// Create a new <see cref="Base16"/> instance from the specified <see cref="ReadOnlySequence{T}"/> value.
74-
/// <remarks>The <see cref="ReadOnlySequence{T}"/> value will be encoded using the <see cref="Encoding.UTF8"/> encoding.</remarks>
75-
/// </summary>
76-
/// <param name="value">The value from which to create a new <see cref="Base16"/> instance.</param>
77-
/// <returns>Returns a new <see cref="Base16"/> instance from the specified <see cref="ReadOnlySequence{T}"/> value.</returns>
43+
/// <inheritdoc/>
7844
public static implicit operator Base16(ReadOnlySequence<char> value) => new(value);
7945
}

OnixLabs.Core/Text/Base16.Equatable.cs

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,46 +12,24 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
using System.Collections.Generic;
1615
using OnixLabs.Core.Linq;
1716

1817
namespace OnixLabs.Core.Text;
1918

2019
public readonly partial struct Base16
2120
{
22-
/// <summary>
23-
/// Checks whether the current object is equal to another object of the same type.
24-
/// </summary>
25-
/// <param name="other">An object to compare with the current object.</param>
26-
/// <returns>Returns <see langword="true"/> if the current object is equal to the other parameter; otherwise, <see langword="false"/>.</returns>
21+
/// <inheritdoc/>
2722
public bool Equals(Base16 other) => other.value.SequenceEqualOrNull(value);
2823

29-
/// <summary>
30-
/// Checks for equality between the current instance and another object.
31-
/// </summary>
32-
/// <param name="obj">The object to check for equality.</param>
33-
/// <returns>Returns <see langword="true"/> if the object is equal to the current instance; otherwise, <see langword="false"/>.</returns>
24+
/// <inheritdoc/>
3425
public override bool Equals(object? obj) => obj is Base16 other && Equals(other);
3526

36-
/// <summary>
37-
/// Serves as a hash code function for the current instance.
38-
/// </summary>
39-
/// <returns>Returns a hash code for the current instance.</returns>
27+
/// <inheritdoc/>
4028
public override int GetHashCode() => value.GetContentHashCode();
4129

42-
/// <summary>
43-
/// Performs an equality comparison between two object instances.
44-
/// </summary>
45-
/// <param name="left">The left-hand instance to compare.</param>
46-
/// <param name="right">The right-hand instance to compare.</param>
47-
/// <returns>Returns <see langword="true"/> if the left-hand instance is equal to the right-hand instance; otherwise, <see langword="false"/>.</returns>
48-
public static bool operator ==(Base16 left, Base16 right) => EqualityComparer<Base16>.Default.Equals(left, right);
30+
/// <inheritdoc/>
31+
public static bool operator ==(Base16 left, Base16 right) => left.Equals(right);
4932

50-
/// <summary>
51-
/// Performs an inequality comparison between two object instances.
52-
/// </summary>
53-
/// <param name="left">The left-hand instance to compare.</param>
54-
/// <param name="right">The right-hand instance to compare.</param>
55-
/// <returns>Returns <see langword="true"/> if the left-hand instance is not equal to the right-hand instance; otherwise, <see langword="false"/>.</returns>
56-
public static bool operator !=(Base16 left, Base16 right) => !EqualityComparer<Base16>.Default.Equals(left, right);
33+
/// <inheritdoc/>
34+
public static bool operator !=(Base16 left, Base16 right) => !left.Equals(right);
5735
}

OnixLabs.Core/Text/Base16.Format.cs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,11 @@ namespace OnixLabs.Core.Text;
1818

1919
public readonly partial struct Base16
2020
{
21-
/// <summary>
22-
/// Tries to format the value of the current instance into the provided span of characters.
23-
/// </summary>
24-
/// <param name="destination">The span in which to write this instance's value formatted as a span of characters.</param>
25-
/// <param name="charsWritten">When this method returns, contains the number of characters that were written in <paramref name="destination" />.</param>
26-
/// <param name="format">A span containing the characters that represent a standard or custom format string that defines the acceptable format for <paramref name="destination" />.</param>
27-
/// <param name="provider">An optional object that supplies culture-specific formatting information for <paramref name="destination" />.</param>
28-
/// <returns>Returns <see langword="true"/> if the formatting was successful; otherwise, <see langword="false"/>.</returns>
29-
bool ISpanFormattable.TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)
30-
{
31-
return ToString(format, provider).TryCopyTo(destination, out charsWritten);
32-
}
21+
/// <inheritdoc/>
22+
bool ISpanFormattable.TryFormat(
23+
Span<char> destination,
24+
out int charsWritten,
25+
ReadOnlySpan<char> format,
26+
IFormatProvider? provider
27+
) => ToString(format, provider).TryCopyTo(destination, out charsWritten);
3328
}

OnixLabs.Core/Text/Base16.Parse.cs

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -18,44 +18,16 @@ namespace OnixLabs.Core.Text;
1818

1919
public readonly partial struct Base16
2020
{
21-
/// <summary>
22-
/// Parses the specified Base-16 encoded <see cref="String"/> value into a <see cref="Base16"/> value.
23-
/// </summary>
24-
/// <param name="value">The Base-16 encoded value to parse.</param>
25-
/// <param name="provider">The format provider that will be used to decode the specified value.</param>
26-
/// <returns>Returns a new <see cref="Base16"/> instance, parsed from the specified Base-16 encoded <see cref="String"/> value.</returns>
21+
/// <inheritdoc/>
2722
public static Base16 Parse(string value, IFormatProvider? provider = null) => Parse(value.AsSpan(), provider);
2823

29-
/// <summary>
30-
/// Parses the specified Base-16 encoded <see cref="ReadOnlySpan{T}"/> value into a <see cref="Base16"/> value.
31-
/// </summary>
32-
/// <param name="value">The Base-16 encoded value to parse.</param>
33-
/// <param name="provider">The format provider that will be used to decode the specified value.</param>
34-
/// <returns>Returns a new <see cref="Base16"/> instance, parsed from the specified Base-16 encoded <see cref="ReadOnlySpan{T}"/> value.</returns>
24+
/// <inheritdoc/>
3525
public static Base16 Parse(ReadOnlySpan<char> value, IFormatProvider? provider = null) => new(IBaseCodec.Base16.Decode(value, provider));
3626

37-
/// <summary>
38-
/// Tries to parse the specified Base-16 encoded <see cref="String"/> value into a <see cref="Base16"/> value.
39-
/// </summary>
40-
/// <param name="value">The Base-16 encoded value to parse.</param>
41-
/// <param name="provider">The format provider that will be used to decode the specified value.</param>
42-
/// <param name="result">
43-
/// A new <see cref="Base16"/> instance, parsed from the specified Base-16 encoded <see cref="String"/> value,
44-
/// or the default <see cref="Base16"/> value if the specified Base-16 encoded <see cref="String"/> could not be parsed.
45-
/// </param>
46-
/// <returns>Returns <see langword="true"/> if the specified Base-16 value was decoded successfully; otherwise, <see langword="false"/>.</returns>
27+
/// <inheritdoc/>
4728
public static bool TryParse(string? value, IFormatProvider? provider, out Base16 result) => TryParse(value.AsSpan(), provider, out result);
4829

49-
/// <summary>
50-
/// Tries to parse the specified Base-16 encoded <see cref="ReadOnlySpan{T}"/> value into a <see cref="Base16"/> value.
51-
/// </summary>
52-
/// <param name="value">The Base-16 encoded value to parse.</param>
53-
/// <param name="provider">The format provider that will be used to decode the specified value.</param>
54-
/// <param name="result">
55-
/// A new <see cref="Base16"/> instance, parsed from the specified Base-16 encoded <see cref="ReadOnlySpan{T}"/> value,
56-
/// or the default <see cref="Base16"/> value if the specified Base-16 encoded <see cref="ReadOnlySpan{T}"/> could not be parsed.
57-
/// </param>
58-
/// <returns>Returns <see langword="true"/> if the specified Base-16 value was decoded successfully; otherwise, <see langword="false"/>.</returns>
30+
/// <inheritdoc/>
5931
public static bool TryParse(ReadOnlySpan<char> value, IFormatProvider? provider, out Base16 result)
6032
{
6133
if (IBaseCodec.Base16.TryDecode(value, provider, out byte[] bytes))

OnixLabs.Core/Text/Base16.To.cs

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,32 +18,15 @@ namespace OnixLabs.Core.Text;
1818

1919
public readonly partial struct Base16
2020
{
21-
/// <summary>
22-
/// Returns a <see cref="String"/> that represents the current object.
23-
/// </summary>
24-
/// <returns>Returns a <see cref="String"/> that represents the current object.</returns>
21+
/// <inheritdoc/>
2522
public override string ToString() => ToString(Base16FormatProvider.Invariant);
2623

27-
/// <summary>
28-
/// Formats the value of the current instance using the specified format.
29-
/// </summary>
30-
/// <param name="formatProvider">The provider to use to format the value.</param>
31-
/// <returns>The value of the current instance in the specified format.</returns>
24+
/// <inheritdoc/>
3225
public string ToString(IFormatProvider? formatProvider) => ToString(null, formatProvider);
3326

34-
/// <summary>
35-
/// Formats the value of the current instance using the specified format.
36-
/// </summary>
37-
/// <param name="format">The format to use.</param>
38-
/// <param name="formatProvider">The provider to use to format the value.</param>
39-
/// <returns>The value of the current instance in the specified format.</returns>
27+
/// <inheritdoc/>
4028
public string ToString(string? format, IFormatProvider? formatProvider) => ToString(format.AsSpan(), formatProvider);
4129

42-
/// <summary>
43-
/// Formats the value of the current instance using the specified format.
44-
/// </summary>
45-
/// <param name="format">The format to use.</param>
46-
/// <param name="formatProvider">The provider to use to format the value.</param>
47-
/// <returns>The value of the current instance in the specified format.</returns>
30+
/// <inheritdoc/>
4831
public string ToString(ReadOnlySpan<char> format, IFormatProvider? formatProvider) => IBaseCodec.Base16.Encode(value, formatProvider);
4932
}

OnixLabs.Core/Text/Base16.cs

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,44 +21,69 @@ namespace OnixLabs.Core.Text;
2121
/// <summary>
2222
/// Represents a Base-16 value.
2323
/// </summary>
24-
/// <param name="value">The <see cref="ReadOnlySpan{T}"/> with which to initialize the <see cref="Base16"/> instance.</param>
25-
public readonly partial struct Base16(ReadOnlySpan<byte> value) : IBaseValue<Base16>
24+
// ReSharper disable MemberCanBePrivate.Global
25+
public readonly partial struct Base16 : IBaseValue<Base16>
2626
{
27-
private readonly byte[] value = value.ToArray();
27+
private readonly byte[] value;
2828

2929
/// <summary>
3030
/// Initializes a new instance of the <see cref="Base16"/> struct.
3131
/// </summary>
32-
/// <param name="value">The <see cref="ReadOnlySequence{T}"/> with which to initialize the <see cref="Base16"/> instance.</param>
33-
// ReSharper disable once MemberCanBePrivate.Global
34-
public Base16(ReadOnlySequence<byte> value) : this(ReadOnlySpan<byte>.Empty) => value.CopyTo(out this.value);
32+
/// <remarks>
33+
/// This constructor is intentionally marked <see langword="private"/> and is used exclusively to initialize the underlying <see cref="byte"/> array.
34+
/// Because <see cref="Base16"/> is designed to be immutable, external array references are not permitted.
35+
/// The overloaded constructors below ensure immutability by creating defensive copies of the provided arrays.
36+
/// </remarks>
37+
/// <param name="value">The value from which to initialize the new <see cref="Base16"/> instance.</param>
38+
private Base16(byte[] value) => this.value = value;
3539

3640
/// <summary>
3741
/// Initializes a new instance of the <see cref="Base16"/> struct.
3842
/// </summary>
39-
/// <param name="value">The <see cref="string"/> with which to initialize the <see cref="Base16"/> instance.</param>
40-
/// <param name="encoding">The <see cref="Encoding"/> which will be used to obtain the underlying value.</param>
41-
// ReSharper disable once MemberCanBePrivate.Global
42-
public Base16(string value, Encoding? encoding = null) : this(encoding.GetOrDefault().GetBytes(value))
43+
/// <param name="value">The value from which to initialize the new <see cref="Base16"/> instance.</param>
44+
public Base16(ReadOnlySpan<byte> value) : this(value.ToArray())
4345
{
4446
}
4547

4648
/// <summary>
4749
/// Initializes a new instance of the <see cref="Base16"/> struct.
4850
/// </summary>
49-
/// <param name="value">The <see cref="char"/> array with which to initialize the <see cref="Base16"/> instance.</param>
50-
/// <param name="encoding">The <see cref="Encoding"/> which will be used to obtain the underlying value.</param>
51-
// ReSharper disable once MemberCanBePrivate.Global
52-
public Base16(char[] value, Encoding? encoding = null) : this(encoding.GetOrDefault().GetBytes(value))
51+
/// <param name="value">The value from which to initialize the new <see cref="Base16"/> instance.</param>
52+
public Base16(ReadOnlyMemory<byte> value) : this(value.ToArray())
5353
{
5454
}
5555

5656
/// <summary>
5757
/// Initializes a new instance of the <see cref="Base16"/> struct.
5858
/// </summary>
59-
/// <param name="value">The <see cref="ReadOnlySequence{T}"/> with which to initialize the <see cref="Base16"/> instance.</param>
60-
/// <param name="encoding">The <see cref="Encoding"/> which will be used to obtain the underlying value.</param>
61-
// ReSharper disable once MemberCanBePrivate.Global
59+
/// <param name="value">The value from which to initialize the new <see cref="Base16"/> instance.</param>
60+
public Base16(ReadOnlySequence<byte> value) : this(value.ToArray())
61+
{
62+
}
63+
64+
/// <summary>
65+
/// Initializes a new instance of the <see cref="Base16"/> struct.
66+
/// </summary>
67+
/// <param name="value">The value from which to initialize the new <see cref="Base16"/> instance.</param>
68+
/// <param name="encoding">The <see cref="Encoding"/> that will be used to transform the specified value, or <see langword="null"/> to use the default <see cref="Encoding"/>.</param>
69+
public Base16(ReadOnlySpan<char> value, Encoding? encoding = null) : this(encoding.GetBytes(value))
70+
{
71+
}
72+
73+
/// <summary>
74+
/// Initializes a new instance of the <see cref="Base16"/> struct.
75+
/// </summary>
76+
/// <param name="value">The value from which to initialize the new <see cref="Base16"/> instance.</param>
77+
/// <param name="encoding">The <see cref="Encoding"/> that will be used to transform the specified value, or <see langword="null"/> to use the default <see cref="Encoding"/>.</param>
78+
public Base16(ReadOnlyMemory<char> value, Encoding? encoding = null) : this(encoding.GetBytes(value.Span))
79+
{
80+
}
81+
82+
/// <summary>
83+
/// Initializes a new instance of the <see cref="Base16"/> struct.
84+
/// </summary>
85+
/// <param name="value">The value from which to initialize the new <see cref="Base16"/> instance.</param>
86+
/// <param name="encoding">The <see cref="Encoding"/> that will be used to transform the specified value, or <see langword="null"/> to use the default <see cref="Encoding"/>.</param>
6287
public Base16(ReadOnlySequence<char> value, Encoding? encoding = null) : this(encoding.GetOrDefault().GetBytes(value))
6388
{
6489
}

0 commit comments

Comments
 (0)