Skip to content

Commit 5c1c284

Browse files
Merge pull request #4 from Open-NET-Libraries/StringSegmentFindExperiement
String segment find experiment
2 parents 700c35e + 101d083 commit 5c1c284

7 files changed

Lines changed: 516 additions & 62 deletions

File tree

Source/EnumValue.cs

Lines changed: 76 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@
1515
namespace Open.Text;
1616

1717
/// <summary>
18-
/// A case struct representing an enum value that can be implicitly coerced from a string.
18+
/// A struct representing an enum value that can be implicitly coerced from a string.
1919
/// </summary>
2020
/// <remarks>String parsing or coercion is case sensitive and must be exact.</remarks>
2121
[SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "Already exposes via a property.")]
2222
[SuppressMessage("Design", "CA1000:Do not declare static members on generic types", Justification = "Intentional")]
23+
[SuppressMessage("Roslynator", "RCS1158:Static member in generic type should use a type parameter.")]
2324
[DebuggerDisplay("{GetDebuggerDisplay()}")]
2425
public readonly struct EnumValue<TEnum>
2526
: IEquatable<EnumValue<TEnum>>, IEquatable<EnumValueCaseIgnored<TEnum>>, IEquatable<TEnum>
@@ -34,29 +35,25 @@ public readonly struct EnumValue<TEnum>
3435
public static Type UnderlyingType => _underlyingType ??= Enum.GetUnderlyingType(typeof(TEnum));
3536

3637
/// <summary>
37-
/// Constructs an EnumValue&lt;<typeparamref name="TEnum"/>&gt; using the provided enum value.
38+
/// Constructs an <see cref="EnumValue{TEnum}"/> using the provided <typeparamref name="TEnum"/> value.
3839
/// </summary>
3940
public EnumValue(TEnum value)
40-
{
41-
Value = value;
42-
}
41+
=> Value = value;
4342

4443
/// <summary>
45-
/// Parses the string value to construct an EnumValue&lt;<typeparamref name="TEnum"/>&gt; instance.
44+
/// Parses the <paramref name="value"/> to construct an <see cref="EnumValue{TEnum}"/>.
4645
/// </summary>
4746
/// <exception cref="ArgumentNullException">value is null.</exception>
4847
public EnumValue(StringSegment value)
49-
{
50-
Value = EnumValue.Parse<TEnum>(value);
51-
}
48+
=> Value = EnumValue.Parse<TEnum>(value);
5249

5350
/// <summary>
54-
/// The enum value that this represents.
51+
/// The <typeparamref name="TEnum"/> value that this represents.
5552
/// </summary>
5653
public readonly TEnum Value { get; }
5754

5855
/// <summary>
59-
/// Returns the string representation of the enum value.
56+
/// Returns the <see cref="string"/> representation of the enum value.
6057
/// </summary>
6158
[MethodImpl(MethodImplOptions.AggressiveInlining)]
6259
public override string ToString() => NameLookup(Value);
@@ -165,7 +162,18 @@ internal static Func<string, ValueLookupResult> ValueLookup
165162
private static IReadOnlyDictionary<string, TEnum>? _ignoreCaseLookup;
166163
internal static IReadOnlyDictionary<string, TEnum> IgnoreCaseLookup
167164
=> LazyInitializer.EnsureInitialized(ref _ignoreCaseLookup,
168-
() => Values.ToDictionary(e => Enum.GetName(typeof(TEnum), e)!, e => e, StringComparer.OrdinalIgnoreCase))!;
165+
() =>
166+
{
167+
// If the enum has duplicate values, we want to use the first one.
168+
var result = new Dictionary<string, TEnum>(StringComparer.OrdinalIgnoreCase);
169+
foreach (var e in Values)
170+
{
171+
var v = Enum.GetName(typeof(TEnum), e);
172+
if (result.ContainsKey(v)) continue;
173+
result[v] = e;
174+
}
175+
return result;
176+
})!;
169177

170178
static Entry[]?[] CreateLookup()
171179
{
@@ -242,7 +250,6 @@ public static int Find(Span<Entry> span, ReadOnlySpan<char> name, StringComparis
242250
return middle;
243251
}
244252

245-
246253
return -1;
247254
}
248255
}
@@ -253,49 +260,58 @@ internal static Entry[]?[] Lookup
253260
() => CreateLookup())!;
254261

255262
/// <summary>
256-
/// Indicates whether this instance matches the enum value of <paramref name="other"/>.
263+
/// Indicates whether this instance matches the <typeparamref name="TEnum"/> value of <paramref name="other"/>.
257264
/// </summary>
258-
/// <returns>true if <paramref name="other"/>'s enum value and this instance's enum value are the same; otherwise false.</returns>
259-
public bool Equals(EnumValue<TEnum> other) => Value.Equals(other.Value);
265+
/// <returns>true if <paramref name="other"/>'s <typeparamref name="TEnum"/> value and this instance's <typeparamref name="TEnum"/> value are the same; otherwise false.</returns>
266+
public bool Equals(EnumValue<TEnum> other)
267+
=> Value.Equals(other.Value);
260268

261269
/// <summary>
262-
/// Compares an EnumValue and EnumValueCaseIgnored for enum equality.
270+
/// Compares an <see cref="EnumValue{TEnum}"/> and <see cref="EnumValueCaseIgnored{TEnum}"/> for <typeparamref name="TEnum"/> equality.
263271
/// </summary>
264-
public static bool operator ==(EnumValue<TEnum> left, EnumValue<TEnum> right) => left.Value.Equals(right.Value);
272+
public static bool operator ==(EnumValue<TEnum> left, EnumValue<TEnum> right)
273+
=> left.Value.Equals(right.Value);
265274

266275
/// <summary>
267-
/// Compares an EnumValue and EnumValueCaseIgnored for enum inequality.
276+
/// Compares an <see cref="EnumValue{TEnum}"/> and <see cref="EnumValueCaseIgnored{TEnum}"/> for <typeparamref name="TEnum"/> inequality.
268277
/// </summary>
269-
public static bool operator !=(EnumValue<TEnum> left, EnumValue<TEnum> right) => !left.Value.Equals(right.Value);
278+
public static bool operator !=(EnumValue<TEnum> left, EnumValue<TEnum> right)
279+
=> !left.Value.Equals(right.Value);
270280

271281
/// <inheritdoc cref="Equals(EnumValue{TEnum})"/>
272-
public bool Equals(EnumValueCaseIgnored<TEnum> other) => Value.Equals(other.Value);
282+
public bool Equals(EnumValueCaseIgnored<TEnum> other)
283+
=> Value.Equals(other.Value);
273284

274285
/// <summary>
275-
/// Compares two EnumValue for enum equality.
286+
/// Compares two <see cref="EnumValue{TEnum}"/> for <typeparamref name="TEnum"/> equality.
276287
/// </summary>
277-
public static bool operator ==(EnumValue<TEnum> left, EnumValueCaseIgnored<TEnum> right) => left.Value.Equals(right.Value);
288+
public static bool operator ==(EnumValue<TEnum> left, EnumValueCaseIgnored<TEnum> right)
289+
=> left.Value.Equals(right.Value);
278290

279291
/// <summary>
280-
/// Compares two EnumValue for enum inequality.
292+
/// Compares two <see cref="EnumValue{TEnum}"/> for <typeparamref name="TEnum"/> inequality.
281293
/// </summary>
282-
public static bool operator !=(EnumValue<TEnum> left, EnumValueCaseIgnored<TEnum> right) => !left.Value.Equals(right.Value);
294+
public static bool operator !=(EnumValue<TEnum> left, EnumValueCaseIgnored<TEnum> right)
295+
=> !left.Value.Equals(right.Value);
283296

284297
/// <summary>
285298
/// Indicates whether this instance matches the provided enum <paramref name="other"/>.
286299
/// </summary>
287300
/// <returns>true if <paramref name="other"/> and this instance's enum value are the same; otherwise false.</returns>
288-
public bool Equals(TEnum other) => Value.Equals(other);
301+
public bool Equals(TEnum other)
302+
=> Value.Equals(other);
289303

290304
/// <summary>
291-
/// Compares an EnumValue and an enum value for enum equality.
305+
/// Compares an <see cref="EnumValue{TEnum}"/> and a <typeparamref name="TEnum"/> value forequality.
292306
/// </summary>
293-
public static bool operator ==(EnumValue<TEnum> left, TEnum right) => left.Value.Equals(right);
307+
public static bool operator ==(EnumValue<TEnum> left, TEnum right)
308+
=> left.Value.Equals(right);
294309

295310
/// <summary>
296-
/// Compares an EnumValue and an enum value for enum inequality.
311+
/// Compares an <see cref="EnumValue{TEnum}"/> and a <typeparamref name="TEnum"/> value for inequality.
297312
/// </summary>
298-
public static bool operator !=(EnumValue<TEnum> left, TEnum right) => !left.Value.Equals(right);
313+
public static bool operator !=(EnumValue<TEnum> left, TEnum right)
314+
=> !left.Value.Equals(right);
299315

300316
/// <inheritdoc />
301317
public override bool Equals(object? obj)
@@ -307,23 +323,28 @@ public override bool Equals(object? obj)
307323
public override int GetHashCode() => Value.GetHashCode();
308324

309325
/// <summary>
310-
/// Implicitly converts an EnumValueCaseInsensitive to an EnumValue.
326+
/// Implicitly converts an <see cref="EnumValueCaseIgnored{TEnum}"/> to an <see cref="EnumValue{TEnum}"/>.
311327
/// Before conversion they are already equivalent.
312328
/// </summary>
313329
public static implicit operator EnumValue<TEnum>(EnumValueCaseIgnored<TEnum> value) => new(value.Value);
314330

315331
/// <summary>
316-
/// Implicitly returns the actual enum contained by the EnumValue.
332+
/// Implicitly returns the actual enum contained by the <see cref="EnumValue{TEnum}"/>.
317333
/// </summary>
318334
public static implicit operator TEnum(EnumValue<TEnum> value) => value.Value;
319335

320336
/// <summary>
321-
/// Implicitly converts an string to an EnumValue of enum type TEnum.
337+
/// Implicitly converts an <typeparamref name="TEnum"/> to an <see cref="EnumValue{TEnum}"/>.
338+
/// </summary>
339+
public static implicit operator EnumValue<TEnum>(TEnum value) => new(value);
340+
341+
/// <summary>
342+
/// Implicitly converts a <see cref="string"/> to an <see cref="EnumValue{TEnum}"/>.
322343
/// </summary>
323344
public static implicit operator EnumValue<TEnum>(StringSegment value) => new(value);
324345

325346
/// <summary>
326-
/// Implicitly converts an string to an EnumValue of enum type TEnum.
347+
/// Implicitly converts a <see cref="string"/> to an <see cref="EnumValue{TEnum}"/>.
327348
/// </summary>
328349
public static implicit operator EnumValue<TEnum>(string value) => new(value);
329350

@@ -374,21 +395,15 @@ public readonly struct EnumValueCaseIgnored<TEnum>
374395
where TEnum : Enum
375396
{
376397
/// <summary>
377-
/// Constructs an EnumValueCaseIgnored&lt;<typeparamref name="TEnum"/>&gt; using the provided enum value.
398+
/// Constructs an <see cref="EnumValueCaseIgnored{TEnum}"/> using the provided enum value.
378399
/// </summary>
379-
public EnumValueCaseIgnored(TEnum value)
380-
{
381-
Value = value;
382-
}
400+
public EnumValueCaseIgnored(TEnum value) => Value = value;
383401

384402
/// <summary>
385-
/// Parses the string value to construct an EnumValueCaseIgnored&lt;<typeparamref name="TEnum"/>&gt; instance.
403+
/// Parses the string value to construct an <see cref="EnumValueCaseIgnored{TEnum}"/> instance.
386404
/// </summary>
387405
/// <exception cref="ArgumentNullException"><paramref name="value"/> is null.</exception>
388-
public EnumValueCaseIgnored(StringSegment value)
389-
{
390-
Value = EnumValue.Parse<TEnum>(value, true);
391-
}
406+
public EnumValueCaseIgnored(StringSegment value) => Value = EnumValue.Parse<TEnum>(value, true);
392407

393408
/// <inheritdoc cref="EnumValue{TEnum}.Value"/>
394409
public readonly TEnum Value { get; }
@@ -400,12 +415,12 @@ public EnumValueCaseIgnored(StringSegment value)
400415
public bool Equals(EnumValue<TEnum> other) => Value.Equals(other.Value);
401416

402417
/// <summary>
403-
/// Compares an EnumValueCaseIgnored and EnumValue for enum equality.
418+
/// Compares an <see cref="EnumValueCaseIgnored{TEnum}"/> and <see cref="EnumValue{TEnum}"/> for <typeparamref name="TEnum"/> equality.
404419
/// </summary>
405420
public static bool operator ==(EnumValueCaseIgnored<TEnum> left, EnumValue<TEnum> right) => left.Value.Equals(right.Value);
406421

407422
/// <summary>
408-
/// Compares an EnumValueCaseIgnored and EnumValue for enum inequality.
423+
/// Compares an <see cref="EnumValueCaseIgnored{TEnum}"/> and <see cref="EnumValue{TEnum}"/> for <typeparamref name="TEnum"/> inequality.
409424
/// </summary>
410425
public static bool operator !=(EnumValueCaseIgnored<TEnum> left, EnumValue<TEnum> right)
411426
=> !left.Value.Equals(right.Value);
@@ -415,13 +430,13 @@ public bool Equals(EnumValueCaseIgnored<TEnum> other)
415430
=> Value.Equals(other.Value);
416431

417432
/// <summary>
418-
/// Compares two EnumValueCaseIgnored for enum equality.
433+
/// Compares two <see cref="EnumValueCaseIgnored{TEnum}"/> for <typeparamref name="TEnum"/> equality.
419434
/// </summary>
420435
public static bool operator ==(EnumValueCaseIgnored<TEnum> left, EnumValueCaseIgnored<TEnum> right)
421436
=> left.Value.Equals(right.Value);
422437

423438
/// <summary>
424-
/// Compares two EnumValueCaseIgnored for enum inequality.
439+
/// Compares two <see cref="EnumValueCaseIgnored{TEnum}"/> for <typeparamref name="TEnum"/> inequality.
425440
/// </summary>
426441
public static bool operator !=(EnumValueCaseIgnored<TEnum> left, EnumValueCaseIgnored<TEnum> right)
427442
=> !left.Value.Equals(right.Value);
@@ -431,13 +446,13 @@ public bool Equals(TEnum other)
431446
=> Value.Equals(other);
432447

433448
/// <summary>
434-
/// Compares an EnumValueCaseIgnored and an enum value for enum equality.
449+
/// Compares an <see cref="EnumValueCaseIgnored{TEnum}"/> and a <typeparamref name="TEnum"/> value for equality.
435450
/// </summary>
436451
public static bool operator ==(EnumValueCaseIgnored<TEnum> left, TEnum right)
437452
=> left.Value.Equals(right);
438453

439454
/// <summary>
440-
/// Compares an EnumValueCaseIgnored and an enum value for enum inequality.
455+
/// Compares an <see cref="EnumValueCaseIgnored{TEnum}"/> and a <typeparamref name="TEnum"/> value for inequality.
441456
/// </summary>
442457
public static bool operator !=(EnumValueCaseIgnored<TEnum> left, TEnum right)
443458
=> !left.Value.Equals(right);
@@ -453,34 +468,40 @@ public override int GetHashCode()
453468
=> Value.GetHashCode();
454469

455470
/// <summary>
456-
/// Implicitly converts an EnumValue to an EnumValueCaseInsensitive.
471+
/// Implicitly converts an <see cref="EnumValue{TEnum}"/> to an <see cref="EnumValueCaseIgnored{TEnum}"/>.
457472
/// Before conversion they are already equivalent.
458473
/// </summary>
459474
public static implicit operator EnumValueCaseIgnored<TEnum>(EnumValue<TEnum> value)
460475
=> new(value.Value);
461476

462477
/// <summary>
463-
/// Implicitly returns the actual enum contained by the EnumValueCaseIgnored.
478+
/// Implicitly returns the actual <typeparamref name="TEnum"/> contained by the <see cref="EnumValueCaseIgnored{TEnum}"/>.
464479
/// </summary>
465480
public static implicit operator TEnum(EnumValueCaseIgnored<TEnum> value)
466481
=> value.Value;
467482

468483
/// <summary>
469-
/// Implicitly converts an string to an EnumValueCaseIgnored of enum type TEnum.
484+
/// Implicitly converts an <typeparamref name="TEnum"/> to an <see cref="EnumValue{TEnum}"/>.
485+
/// </summary>
486+
public static implicit operator EnumValueCaseIgnored<TEnum>(TEnum value)
487+
=> new(value);
488+
489+
/// <summary>
490+
/// Implicitly converts a <see cref="string"/> to an <see cref="EnumValueCaseIgnored{TEnum}"/>.
470491
/// </summary>
471492
public static implicit operator EnumValueCaseIgnored<TEnum>(StringSegment value)
472493
=> new(value);
473494

474495
/// <summary>
475-
/// Implicitly converts an string to an EnumValueCaseIgnored of enum type TEnum.
496+
/// Implicitly converts a <see cref="string"/> to an <see cref="EnumValueCaseIgnored{TEnum}"/>.
476497
/// </summary>
477498
public static implicit operator EnumValueCaseIgnored<TEnum>(string value)
478499
=> new(value);
479500

480501
private string GetDebuggerDisplay()
481502
{
482503
var eType = typeof(TEnum);
483-
return $"{eType.Name}.{Value} [EnumValueCaseIgnored<{eType.FullName}>]";
504+
return $"{eType.Name}.{ToString()} [EnumValueCaseIgnored<{eType.FullName}>]";
484505
}
485506
}
486507

Source/Extensions._.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,6 @@ public static int GetHashCodeFromChars(this ReadOnlySpan<char> chars, StringComp
484484

485485
break;
486486
}
487-
488487
}
489488

490489
return hash + length;

Source/Open.Text.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<RepositoryUrl>https://github.com/Open-NET-Libraries/Open.Text</RepositoryUrl>
2020
<RepositoryType>git</RepositoryType>
2121
<PackageTags>string, span, enum, readonlyspan, text, format, split, trim, equals, trimmed equals, first, last, preceding, following, stringbuilder, extensions, stringcomparable, spancomparable, stringsegment, splitassegment</PackageTags>
22-
<Version>6.6.3</Version>
22+
<Version>6.7.0</Version>
2323
<PackageReleaseNotes></PackageReleaseNotes>
2424
<PackageLicenseExpression>MIT</PackageLicenseExpression>
2525
<PublishRepositoryUrl>true</PublishRepositoryUrl>

0 commit comments

Comments
 (0)