型安全なビットフラグ集合の実装例

Kotlin での、型安全で不変なビットフラグ集合の実装例。
（他の言語でも概ね同様にして型安全なビットフラグ集合を実現できるだろう。）

```kotlin
class Flags private constructor(
        private val bits: Int
) {
    companion object {
        val EMPTY = Flags(0b0000)

        val FLAG_A = Flags(0b0001)
        val FLAG_B = Flags(0b0010)
        val FLAG_C = Flags(0b0100)
        val FLAG_D = Flags(0b1000)
    }

    operator fun plus(flags: Flags): Flags =
            Flags(this.bits or flags.bits)

    operator fun minus(flags: Flags): Flags =
            Flags(this.bits and flags.bits.inv())

    operator fun times(flags: Flags): Flags =
            Flags(this.bits and flags.bits)

    operator fun contains(flags: Flags): Boolean =
            this * flags == flags

    override fun equals(other: Any?) = when {
        this === other -> true
        other !is Flags -> false
        else -> this.bits == other.bits
    }

    override fun hashCode() = bits.hashCode()

    override fun toString() =
            "${Flags::class.java.simpleName}(${::bits.name}=0b${bits.toString(2)})"
}
```

使用方法

```kotlin
    // plus
    val ab = Flags.FLAG_A + Flags.FLAG_B // -> 0b0011
    val abc = ab + Flags.FLAG_C // -> 0b0111
    ab + Flags.FLAG_A  // -> 0b0011 既に立っているフラグをさらに立てても影響なし

    // minus
    val bc = abc - Flags.FLAG_A // -> 0b0110
    bc - Flags.FLAG_A // -> 0b0110 既に倒れているフラグをさらに倒しても影響なし

    // times
    ab * bc // -> 0b0010

    // contains
    Flags.FLAG_A in ab // -> true
    Flags.FLAG_C in ab // -> false
    Flags.EMPTY in ab // -> true
    ab in abc // -> true 複数のフラグの場合、
    ab in bc // -> false 全てが含まれているかどうかを返す

    // equals
    ab + Flags.FLAG_C == abc // -> true
    ab == bc // -> false
```

## 解説

上から順に、簡単に解説する。

```kotlin
class
```

単なる `class` にする。
これにより、派生クラスは実装できない。

`data class` にはしない。
不正なプロパティ値のインスタンスが他所で生成されないようにする必要があり、そのため後述するようにコンストラクターを `private` にするのだが、
`data class` にしてしまうと、メンバ関数 `copy` が自動的に定義・実装され、それを用いると任意のプロパティ値を持つインスタンスを生成できるため。→https://kotlinlang.org/docs/reference/data-classes.html

```kotlin
private constructor
```

不正なプロパティ値のインスタンスが他所で生成されないよう、コンストラクターを `private` にする。

```kotlin
private val bits: Int
```

各ビットフラグを保持するビットフィールド。

- 他所から直接参照されないよう `private` にする。
- 不変にするため `val` にする。
- ここでは `Int` を使用しているが、ビットフラグの数が多い場合は `Long` や [`java.util.BitSet`](https://docs.oracle.com/javase/10/docs/api/java/util/BitSet.html)を使うとよい。[^1]

[^1]: クラスを分割することを検討した方が良いとは思うが。 `Int` でも32ビットもあるので。

```kotlin
    companion object {
        val EMPTY = Flags(0b0000)

        val FLAG_A = Flags(0b0001)
        val FLAG_B = Flags(0b0010)
        val FLAG_C = Flags(0b0100)
        val FLAG_D = Flags(0b1000)
    }
```

各ビットフラグの定義を `companion object` のメンバ（他の言語でのクラスメンバに当たる）として行う。
いずれのフラグも立っていない状態を表す `EMPTY` も忘れず定義しよう。（全てのフラグが立っている状態を表す `FULL` もあると便利かもしれない。）

2進数リテラルは接頭辞 `0b` をつけることで記述できる。
また、（今回は使用していないが）桁区切りに `_` を使用できるので、フラグ数が多い場合は4桁ごとにいれるとよい。例： `val FLAG_E = Flags(0b0001_0000)`

```kotlin
    operator fun plus(flags: Flags): Flags =
            Flags(this.bits or flags.bits)
```

`+` 演算でフラグを立てられるよう、演算子をオーバーロードする。

```kotlin
    operator fun minus(flags: Flags): Flags =
            Flags(this.bits and flags.bits.inv())
```

`-` 演算でフラグを倒せるよう、演算子をオーバーロードする。

```kotlin
    operator fun times(flags: Flags): Flags =
            Flags(this.bits and flags.bits)
```

`*` 演算で共通のフラグを得られるよう、演算子をオーバーロードする。

```kotlin
    operator fun contains(flags: Flags): Boolean =
            this * flags == flags
```

`in` 演算でフラグが含まれているかどうかを得られるよう、演算子をオーバーロードする。

```kotlin
    override fun equals(other: Any?) = when {
        this === other -> true
        other !is Flags -> false
        else -> this.bits == other.bits
    }

    override fun hashCode() = bits.hashCode()
```

`data class` ではないため、メンバ関数 `equals` および `hashCode` をオーバーライドする必要がある。

```kotlin
    override fun toString() =
            "${Flags::class.java.simpleName}(${::bits.name}=0b${bits.toString(2)})"
```

`toString` 関数をオーバーライドして、`Flags(bits=0x1111)` の形式の文字列に変換できるようにする。 `bits` プロパティ値の出力を固定桁数にするのも良いだろう。

／以上