Haxe - sending enum as flags to a function
Asked Answered
H

2

6

I'm just trying to convert my code from C# to Haxe NME. I use enums as flags.

[Flags]
enum State
{
    StateOne    = 1,
    StateTwo    = 2,
    StateThree  = 4
}

And use it

if (someObj.HasState(State.StateOne | State.StateTwo))
{
    // Contains both the states. Do something now.
}

I had no idea on how to do this in Haxe NME.

Thanks.

Hileman answered 16/5, 2013 at 6:10 Comment(2)
I recently wrote a blogpost on this topic; Biwise operations made easy with Haxe blog.stroep.nl/2015/08/biwise-operations-made-easy-with-haxeClassicism
@MarkKnol Wow, that's a really nice article. Will be helpful if I did ever use Haxe again.Hileman
H
1

I've managed to find it. I had trouble using enums but I had been successful using constants. This is the simple test file I used.

package ;

class FlagsTest
{

    static inline var FLG_1:Int = 1;
    static inline var FLG_2:Int = 2;

    public static function main() : Void
    {
        var flag:Int = FLG_1;
        if (hasFlag(flag, FLG_1))
        {
            trace ("Test 1 passed");
        }
        flag |= FLG_2;
        if (hasFlag(flag, FLG_2))
        {
            trace ("Test 2 passed");
        }
    }

    public static function hasFlag( flags:Int, flag:Int ) : Bool
    {
        return ((flags & flag) == flag) ? true : false;
    }

}

Output:

FlagsTest.hx line 14: Test 1 passed
FlagsTest.hx line 19: Test 2 passed
Hileman answered 16/5, 2013 at 13:37 Comment(0)
T
13

In Haxe 3, there is haxe.EnumFlags. This uses Haxe 3 Abstract Types which basically wrap an underlying type, in this case, it uses an Int, just like you have done - but then it wraps it up in a pretty API so you don't have to worry about the details.

Here is some sample code:

import haxe.EnumFlags;

class EnumFlagTest 
{
    static function main()
    {
        var flags = new EnumFlags<State>();
        flags.set(StateOne);
        flags.set(StateTwo);
        flags.set(StateThree);
        flags.unset(StateTwo);

        if (flags.has(StateOne)) trace ("State One active");
        if (flags.has(StateTwo)) trace ("State Two active");
        if (flags.has(StateThree)) trace ("State Three active");

        if (flags.has(StateOne) && flags.has(StateTwo)) trace ("One and Two both active");
        if (flags.has(StateOne) && flags.has(StateThree)) trace ("One and Three both active");
    }
}

enum State
{
    StateOne;
    StateTwo;
    StateThree;
}

All of this works is stored as a standard Int, and uses integer operators like you have done, so it should be pretty fast (no wrapping in an external object). If you want to see how it works under the box, the source code for EnumFlags can be viewed here.

If you're still on Haxe 2, then you could create an object that is really similar, but of course, it has to create an object as well as the integer, so if you're doing thousands (millions?) of them then you might get a slow down. The equivalent code, that should work with Haxe 2 (though I haven't checked):

class MyEnumFlags<T:EnumValue>
{
    var i:Int;

    public function new(?i=0)
    {
        this.i = i;
    }

    public inline function has( v : T ) : Bool {
        return i & (1 << Type.enumIndex(v)) != 0;
    }

    public inline function set( v : T ) : Void {
        i |= 1 << Type.enumIndex(v);
    }

    public inline function unset( v : T ) : Void {
        i &= 0xFFFFFFF - (1 << Type.enumIndex(v));
    }

    public inline static function ofInt<T:EnumValue>( i : Int ) : MyEnumFlags<T> {
        return new MyEnumFlags<T>(i);
    }

    public inline function toInt() : Int {
        return i;
    }
}
Thief answered 17/5, 2013 at 4:25 Comment(3)
Seems easier. But since I'm trying to use Haxe 2.06 (I'm not allowed to upgrade that in the school) I'll stick to my method. Thanks for the response. Learned that today.Hileman
I've added a copy of some code that should behave the same on Haxe 2, except that it uses a class/object rather than the fancy abstract usage, so performance would be a little bit slower if you were doing ALOT of flags. And it might not work on Neko 1.* because it has weird issues with 32bit ints that I never understood. But it might still be useful to you :)Bellwether
A small doubt. Why use i &= 0xFFFFFFF - (1 << Type.enumIndex(v)); instead of i &= (Type.enumIndex(v) >> 1);? Is there any difference?Hileman
H
1

I've managed to find it. I had trouble using enums but I had been successful using constants. This is the simple test file I used.

package ;

class FlagsTest
{

    static inline var FLG_1:Int = 1;
    static inline var FLG_2:Int = 2;

    public static function main() : Void
    {
        var flag:Int = FLG_1;
        if (hasFlag(flag, FLG_1))
        {
            trace ("Test 1 passed");
        }
        flag |= FLG_2;
        if (hasFlag(flag, FLG_2))
        {
            trace ("Test 2 passed");
        }
    }

    public static function hasFlag( flags:Int, flag:Int ) : Bool
    {
        return ((flags & flag) == flag) ? true : false;
    }

}

Output:

FlagsTest.hx line 14: Test 1 passed
FlagsTest.hx line 19: Test 2 passed
Hileman answered 16/5, 2013 at 13:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.