3

I've been using the "const iota" solution for enum like structures (see here). But recently I've hit a little SNAFU - one of my enums has reached it's limit of 64b (I'm using int64 consts). Any ideas, short of pouring myself into and over the hellish underbelly of math/big?

[Edit: Added example code]

package testy

import (
    "fmt"
    "strings"
     "strconv"
)

type testyEnum int64

const (
    TE1 testyEnum = 1 << iota
    TE2
    TE3
    TE4
    TE5
    TE6
    TE7
    TE8
    TE9
    TE10
    TE11
    TE12
    TE13
    TE14
    TE15
    TE16
    TE17
    ... (list shortened)
    TE107
    TE108
    TE109
)

//HasFlag returns true if the caller has all of the flags from the parameter
func (obj testyEnum) HasFlag(right testyEnum) bool {
    return obj & right == right
}

//ContainsSomeFlagOf returns true if the caller and the parameter share some flags.
func (obj testyEnum) ContainsSomeFlagOf(right testyEnum) bool {
    return obj&right != 0
}

//SharedFlags returns the shared flags of enum and parameter
func (obj testyEnum) SharedFlags(right testyEnum) testyEnum {
    return obj & right
}

//AddFlag(obj testyEnum) adds flag right to the enum
func (obj *testyEnum) AddFlag(right testyEnum) {
    *obj = *obj|right
}

//RemoveFlag(obj testyEnum) removes flag right to the enum. If any of the flags from right where not set in obj.
func (obj *testyEnum) RemoveFlag(right testyEnum) {
    shared := obj.SharedFlags(right)
    *obj = *obj^shared
}

//ToInt(obj testyEnum) returns the value of the enum as int
func (obj *testyEnum) ToInt() int {
    return int(*obj)
}

//ToStringSlice returns a slice of strings with all the flags that are set
func (obj *testyEnum) ToStringSlice() []string {
    var flags []string

    if obj.HasFlag(TE1) {
        flags = append(flags, "TE1")
    }

    if obj.HasFlag(TE2) {
        flags = append(flags, "TE2")
    }

    if obj.HasFlag(TE3) {
        flags = append(flags, "TE3")
    }

    if obj.HasFlag(TE4) {
        flags = append(flags, "TE4")
    }

    if obj.HasFlag(TE5) {
        flags = append(flags, "TE5")
    }

    if obj.HasFlag(TE6) {
        flags = append(flags, "TE6")
    }

    if obj.HasFlag(TE7) {
        flags = append(flags, "TE7")
    }

    if obj.HasFlag(TE8) {
        flags = append(flags, "TE8")
    }

    if obj.HasFlag(TE9) {
        flags = append(flags, "TE9")
    }

    if obj.HasFlag(TE10) {
        flags = append(flags, "TE10")
    }

    if obj.HasFlag(TE11) {
        flags = append(flags, "TE11")
    }

    if obj.HasFlag(TE12) {
        flags = append(flags, "TE12")
    }

    if obj.HasFlag(TE13) {
        flags = append(flags, "TE13")
    }

    if obj.HasFlag(TE14) {
        flags = append(flags, "TE14")
    }

    if obj.HasFlag(TE15) {
        flags = append(flags, "TE15")
    }

    if obj.HasFlag(TE16) {
        flags = append(flags, "TE16")
    }

    ... (ditto)

    if obj.HasFlag(TE107) {
        flags = append(flags, "TE107")
    }

    if obj.HasFlag(TE108) {
        flags = append(flags, "TE108")
    }

    if obj.HasFlag(TE109) {
        flags = append(flags, "TE109")
    }

    return flags
}

//String returns a string representation of the enum
func (obj testyEnum) String() string {
    flags := obj.ToStringSlice()
    if len(flags) > 0 {
        return fmt.Sprintf("testyEnum{%d(%s)}", int(obj), strings.Join(flags, "|"))
    }

    return "testyEnum{0()}"
}
Community
  • 1
  • 1
  • By "enum" I take it you mean not just a set of constants with distinct values, but more specifically, a set of constants with distinct *power-of-two* values that can be used with bitwise-or and so on? – ruakh Jan 09 '16 at 03:09
  • Can you include a minimal amount of background and code in your question? At the moment it's a guess what you're actually trying to do (and so hard to give helpful answers). – Paul Hankin Jan 09 '16 at 03:09
  • The code is pretty much exactly what you see in the link that's included, except that my const list is 64 items long (and is about to grow) and I've added a few bells 'n whistles (ContainsSomeFlagOf, etc). – Herp Derpson Jan 09 '16 at 03:19
  • Background wise, I'm using these enums to control flow in little game thingy I'm building. Every action in the game has these enums to control flow through the program. Basically I'm building a tiny "action compiler". Don't really wanna go the command string route, all that string manipulation gives me the willies. I'm more than open for suggestions on different solutions though. – Herp Derpson Jan 09 '16 at 03:37
  • https://godoc.org/?q=bitset – kostya Jan 09 '16 at 03:55
  • If you need more than 64 bits a uint64 won't do, but two uint64 might like in `type testyEnum struct { a, b uint64 }`. Setting up the const requires more typing. – Volker Jan 09 '16 at 09:30
  • 2
    @HerpDerpson math/big.(*int) actually has convenient [Bit](https://golang.org/pkg/math/big/#Int.Bit) and [SetBit](https://golang.org/pkg/math/big/#Int.SetBit) methods. Or divide your actions into multiple types, each with N<64. – Ainar-G Jan 09 '16 at 11:50
  • Why not give the enums sequential integers rather than powers of 2? – Amnon Jan 09 '16 at 23:59
  • @Amnon if the enum represents a bit mask with multiple values OR-ed together, they need to be powers of 2 – andlabs Jan 10 '16 at 04:55
  • Amnon what @andlabs said. I'm using a *FLAGGED* enum, not just enum. I need to be able to construct things like PERFORMER|REQUIRED|GUID, PERFORMER|STATUS and PERFORMER|SKILL|LEVEL|REQUIRED etc. I've been looking into doing this as string compiler, but that requires ALOT of design upfront (as in, designing a whole action language with lexical and syntactic parsing) - I think it might be Herp-Derpsons-School-Of-OverDesign worthy endeavor. Before I do that I'm gonna give kostya's and Volker's solution a little twirl. – Herp Derpson Jan 10 '16 at 15:46
  • @Volker I wouldnt be able to do TE1|TE65 then... mind you, could make a function that does pretty much the same TE1.AddFlag(flag unit64)... hmm. Food for thought. – Herp Derpson Jan 10 '16 at 15:58
  • Yeah, I think you're either going to have to either use multiple bitfields, a structure of `bool`s, or math/big.Int. Good luck. – andlabs Jan 10 '16 at 16:35
  • Sit. rep: I ended up using the bitset @kostya recommended. It's not ideal, but works. Con: heavy in use (you can't go TE1|TE2, it uses functions; VarName := TE1.Union(TE2), or MakeTEnum(TE1...). Ended up writing a little package that compiles list of enum names into a .go file. Pro: enum takes maximum 7bits more than it needs.I recommend that [bitset](https://godoc.org/?q=bitset) package for all your bitset needs. I'm sure that using big.Int will have all the same problems so I'm going with this for now. Thanks ya'll for all your valuable input! – Herp Derpson Jan 17 '16 at 14:47

0 Answers0