**** A Flag represents many states by setting and clearing bits on a Int. ** ** Using Ints as flags is still valid, but the Flags class gives superior debugging info. An ** example Flags class:** ** pre>** const class MyFlags : Flags {** static const MyFlags one := MyFlags(1, "one")** static const MyFlags two := MyFlags(2, "two")** static const MyFlags three := MyFlags(3, "three")** static const MyFlags four := MyFlags(4, "four")** ** new make(Int flag, Str? name) : super(flag, name) { }** new makeFromVariant(Variant variant) : super(variant) { } ** }** <pre** ** Set and clear bits by using '+' and '-' operators:** ** pre>** (MyFlags.two + MyFlags.two) .toStr --> two** (MyFlags.two - MyFlags.four).toStr --> two** <pre** ** Multiple flags may be set:** ** pre>** (MyFlags.one + MyFlags.four).toStr --> one|four** (MyFlags.two + MyFlags.four).toStr --> two|four** <pre** ** Flags are automatically coalesced:** ** pre>** (MyFlags.one + MyFlags.three) .toStr --> three ** <pre** ** Unknown flags are presented as numbers:** ** pre>** (MyFlags(16)) .toStr --> (18)** (MyFlags(10)) .toStr --> two|(8)** (MyFlags(27)) .toStr --> three|(8)|(16)** <pre** ** Every 'Flags' subclass needs to declare the following ctor to fulfil the variant surrogate ** contract:** ** pre>** new makeFromVariant(Variant variant) : super(variant) { }** <pre** constclass Flag {const Int valueprivateconst Str? pName Str name { get { pName == null ? computeName : pName }private set {}}protectednew make(Int value, Str? name := null){this.value = value;this.pName = name;if(name != null && name.isEmpty)throw FancomErr("Flag name can not be empty")}** Add Flag b. Shortcut is a + b. @Operator This plus(Flag b){ newValue := value.or(b.value) newVariant := Variant(newValue)return Helper.toVariantSurrogate(this.typeof, newVariant)as Flag}** Removes Flag b. Shortcut is a - b. @Operator This minus(Flag b){ newValue := value.and(b.value.not) newVariant := Variant(newValue)return Helper.toVariantSurrogate(this.typeof, newVariant)as Flag}** Returns 'true' if the given flag is set on this object. Bool contains(Flag flag){ value.and(flag.value) == flag.value}override Bool equals(Obj? obj){if(obj == null)returnfalseif(!obj.typeof.fits(Flag#))returnfalsereturn(obj as Flag).value == value}override Int hash(){return value.hash}override Str toStr(){ name}// ---- Variant Surrogate Methods ------------------------------------------------------------- ** Variant surrogate ctor new makeFromVariant(Variant variant){this.value = variant.asIntthis.pName = null}** Variant surrogate method Variant toVariant(){ Variant(value)}// ---- Private Methods ----------------------------------------------------------------------- private Str computeName(){ Flag[] match := [,] flags := this.findFlags value := this.valuewhile(value > 0){ flag := flags.find |flag| { flag.value != 0 && flag.value.and(value) == flag.value}if(flag == null){ bit := findSetBits(value)[0] flag = Flag(bit, "($bit)")} match.add(flag) value -= flag.value}if(match.isEmpty && !flags.isEmpty && flags[-1].value == 0) match.add(flags[-1])return match .sort |f1, f2| {(f1 as Flag).value <=> (f2 as Flag).value } .map |flag| { flag.pName } .join("|")}private Flag[] findFlags(){return typeof.fields .findAll |field| { field.isStatic && field.type == typeof} .map |field| { field.get} .sort |f1, f2| {// inverse value order - required for finding composites(f2 as Flag).value <=> (f1 as Flag).value}}private Int[] findSetBits(Int value){// I'm gonna take a leap of faith that no-one uses the MSB of a 64 signed long!(63..0) .map |i| { 2.pow(i)} .findAll |bit| { value.and(bit) == bit }}}