2

I am playing with Span in C#.

Am I right that I cannot use switch statement with span I have to write methods like this?

 private int GetNumberOfLegs(ReadOnlySpan<char> animal)
 {
     if (animal.SequenceEqual("dog".AsSpan()))
        return 4;
     if (animal.SequenceEqual("cat".AsSpan()))
        return 4;
     if (animal.SequenceEqual("spider".AsSpan()))
        return 8;
     if (animal.SequenceEqual("bird".AsSpan()))
        return 2;

    throw new NotSupportedException($"Uknown animal {animal.ToString()}");
 }

Is there better way to express this algorithm with Span?

Tomas Kubes
  • 23,880
  • 18
  • 111
  • 148
  • Did you try to use a `switch` statement? What happened? – Camilo Terevinto Feb 24 '19 at 15:59
  • Constant value is expected. – Tomas Kubes Feb 24 '19 at 16:03
  • Could you convert `ReadOnlySpan` to `string` and then leverage switch statement? – Johnny Feb 24 '19 at 16:08
  • 3
    I don't want to convert ReadOnlySpan to string, because it would be allocation on heap and I need to write extra fast realitme code without any heap allocation - no garbage collections. – Tomas Kubes Feb 24 '19 at 16:12
  • 3
    The normal switch-over-string in C# works by materialising a `Dictionary` with an entry for each case block. So to do the same thing with Span you would need to iterate the span of chars just once to generate a hash-code, then switch on that and only perform a string comparison if there’s a hash-code collission. – Dai Feb 24 '19 at 16:27

1 Answers1

2

Abusing pattern matching could help:

private int GetNumberOfLegs(ReadOnlySpan<char> animal)
{
    switch (animal)
    {
        case var dog when dog.SequenceEqual("dog".AsSpan()):
            return 4;
        case var cat when cat.SequenceEqual("cat".AsSpan()):
            return 4;
        case var spider when spider.SequenceEqual("spider".AsSpan()):
            return 8;
        case var bird when bird.SequenceEqual("bird".AsSpan()):
            return 2;
    }

    throw new NotSupportedException($"Uknown animal {animal.ToString()}");
}
GSerg
  • 76,472
  • 17
  • 159
  • 346
  • 1
    This has `O(n * m)` runtime (where `n` is the length of the string and `m` is the number of cases) - it's the same thing as a bunch of `if/else if` statements. I think `switch` should be reserved for near-`O(1)` cases. – Dai Feb 27 '19 at 17:00
  • @Dai I agree, but I can't think of a better way to use `switch` here, which is kind of an academic exercise at this point. – GSerg Feb 27 '19 at 17:14
  • SequenceEquals is slower than MemoryExtensions.Equals https://stackoverflow.com/a/52680582/56621 – Alex from Jitbit Jul 12 '23 at 13:26