Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question How to iterate enum values with Burst?

Discussion in 'Burst' started by scottjdaley, Nov 6, 2020.

  1. scottjdaley

    scottjdaley

    Joined:
    Aug 1, 2013
    Posts:
    152
    Let's say I have an enum like the following:
    Code (CSharp):
    1. public enum Direction
    2. {
    3.     North,
    4.     East,
    5.     South,
    6.     West,
    7. }
    Ideally, I would like to write code like this:
    Code (CSharp):
    1. foreach (Direction direction in Enum.GetValues(typeof(Direction)))
    2. {
    3.     // ...
    4. }
    However, since Burst does not support Enum methods (yet?), I'm trying to find the best alternative. The first thing I tried was creating a static array field that had contained all of the enum values, like so:
    Code (CSharp):
    1. public static readonly Direction[] AllDirections = {
    2.     Direction.North,
    3.     Direction.East,
    4.     Direction.South,
    5.     Direction.West
    6. };
    This still isn't great, as I have to keep this array in sync with the enum, but its good enough for me. However, this results in the following error when I try to call it from a burst-compiled Entities.ForEach query:
    I tried changing the enum type to be explicit as int or byte but that didn't help. I'm not sure if this is a bug in burst or some limitation that I'm not aware of. The only workaround I found was to create a wrapper struct type like so:
    Code (CSharp):
    1. public struct DirectionWrapper
    2. {
    3.     public static readonly DirectionWrapper[] AllDirections =
    4.     {
    5.         new DirectionWrapper { Value = Direction.North },
    6.         new DirectionWrapper { Value = Direction.East },
    7.         new DirectionWrapper { Value = Direction.South },
    8.         new DirectionWrapper { Value = Direction.West },
    9.     };
    10.  
    11.     public Direction Value;
    12.  
    13.     public static implicit operator Direction(DirectionWrapper wrapper) => wrapper.Value;
    14. }
    I can then iterate directions like this:
    Code (CSharp):
    1. foreach (Direction direction in DirectionWrapper.AllDirections)
    2. {
    3.     // ...
    4. }
    This works, but it seems like there has to be a better option. Any suggestions? Thanks!
     
  2. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    677
    You can initialize those array at runtime using a static constructor
     
  3. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,574
    Burst has no problem with enums, since these are just numbers.
    You can put enum even in IComponentData.

    But since you have

    Code (CSharp):
    1. public enum Direction
    2. {
    3.     North = 0,
    4.     East = 1,
    5.     South = 2,
    6.     West = 3,
    7. }
    8.  
    9. struct DirectionComponent : IComponentData { public Direction direction } ;
    10.  
    You can access enum values in bursted jobs by enum itself, or by assigned value.
    Code (CSharp):
    1. var directionComponent = new DirectionComponent () { direction = Direction.South }
    2. // OR
    3. var directionComponent = new DirectionComponent () { direction = (Direction) 2 }
    Or make DirectionComponent to store int.

    And if you just want to iterate, so knowing number of elements in enum, you can run for loop.
     
  4. Sarkahn

    Sarkahn

    Joined:
    Jan 9, 2013
    Posts:
    440
    You should be fine accessing this inside burst. Maybe you were assigning it to a local variable?

    This is okay
    Code (CSharp):
    1. for( int i = 0; i < AllDirections.Length; ++i )
    This is not
    Code (CSharp):
    1. var arr = AllDirections;
    2. for(int i = 0; i < arr.Length; ++i)
    But like Antypodish said you could just assign your enums numbers 0-3, then do a regular for loop and convert the index to your enum value.
     
  5. tim_jones

    tim_jones

    Unity Technologies

    Joined:
    May 2, 2019
    Posts:
    282
  6. frimarichard

    frimarichard

    Joined:
    Jul 24, 2017
    Posts:
    31
    A useful trick is to assign a known value as the final value inside the enum.

    Code (CSharp):
    1. public enum Direction
    2. {
    3.     North,
    4.     East,
    5.     South,
    6.     West,
    7.     Max
    8. }
    So that you can do this:

    Code (CSharp):
    1. for (Direction direction = 0; direction < Direction.Max; direction++)
    2. {
    3.     Debug.Log($"Direction: {direction}");
    4. }
    5.  
    Of course, this only works if all values are sequential and start at 0.
     
  7. scottjdaley

    scottjdaley

    Joined:
    Aug 1, 2013
    Posts:
    152
    I should have clarified. The code that produces the error in my original post is when I try to do a
    foreach
    loop over AllDirections. A normal for loop that looks up the Direction from the static array works just fine.

    Specifically, let's say I have the following:
    Code (CSharp):
    1. public struct DirectionHelper
    2. {
    3.     public static readonly Direction[] AllDirections =
    4.     {
    5.         Direction.North,
    6.         Direction.East,
    7.         Direction.South,
    8.         Direction.West
    9.     };
    10. }
    11.  
    This works fine:
    Code (CSharp):
    1. for (int i = 0; i < DirectionHelper.AllDirections.Length; i++)
    2. {
    3.     Direction direction = DirectionHelper.AllDirections[i];
    4.     // ...
    5. }
    But this produces a burst error:
    Code (CSharp):
    1. foreach (Direction direction in DirectionHelper.AllDirections)
    2. {
    3.     // ...
    4. }
    So I guess the problem is that burst doesn't support GetEnumerator() on enum arrays?

    Burst 1.4.1
    Unity 2020.2.0b9

    That is a great idea, thanks! Allows me to remove my static "max" fields that I had added to do the same thing, but were easily getting out of sync.
     
  8. tim_jones

    tim_jones

    Unity Technologies

    Joined:
    May 2, 2019
    Posts:
    282
    @scottjdaley thank you for the extra details. I'm following up with the team, but this does look like a bug - if so, we'll work on a fix.
     
  9. scottjdaley

    scottjdaley

    Joined:
    Aug 1, 2013
    Posts:
    152
    @tim_jones Awesome, thanks!

    I also greatly appreciate the other ideas mentioned in this thread.