summaryrefslogtreecommitdiff
path: root/src/KingSystem/Utils/AtomicLongBitFlag.h
blob: f5b2c31b43b64754fa3d13b4254ff8de523ade86 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#pragma once

#include <array>
#include <type_traits>

#include <basis/seadTypes.h>
#include <container/seadSafeArray.h>
#include <math/seadMathCalcCommon.h>
#include <thread/seadAtomic.h>

namespace ksys::util {

template <s32 N, typename Enum>
class AtomicLongBitFlag {
public:
    using Word = sead::Atomic<u32>;

    void makeAllZero() { mStorage.fill(0); }
    void makeAllOne() { mStorage.fill(~Word(0)); }

    Word& getWord(Enum bit);
    const Word& getWord(Enum bit) const;

    bool isZero() const;

    bool setBit(Enum bit);
    bool resetBit(Enum bit);
    bool changeBit(Enum bit, bool on);
    bool isOnBit(Enum bit) const;
    bool isOffBit(Enum bit) const;

protected:
    static constexpr s32 BitsPerWord = 8 * sizeof(Word);

    static_assert(N % BitsPerWord == 0, "N must be a multiple of the number of bits per word");
    sead::SafeArray<Word, N / BitsPerWord> mStorage{};
};

template <s32 N, typename Enum>
inline typename AtomicLongBitFlag<N, Enum>::Word& AtomicLongBitFlag<N, Enum>::getWord(Enum bit) {
    return mStorage[s32(bit) / BitsPerWord];
}

template <s32 N, typename Enum>
inline const typename AtomicLongBitFlag<N, Enum>::Word&
AtomicLongBitFlag<N, Enum>::getWord(Enum bit) const {
    return mStorage[s32(bit) / BitsPerWord];
}

template <s32 N, typename Enum>
inline bool AtomicLongBitFlag<N, Enum>::setBit(Enum bit) {
    return getWord(bit).setBitOn(s32(bit) % BitsPerWord);
}

template <s32 N, typename Enum>
inline bool AtomicLongBitFlag<N, Enum>::resetBit(Enum bit) {
    return getWord(bit).setBitOff(s32(bit) % BitsPerWord);
}

template <s32 N, typename Enum>
inline bool AtomicLongBitFlag<N, Enum>::changeBit(Enum bit, bool on) {
    if (on)
        return setBit(bit);
    else
        return resetBit(bit);
}

template <s32 N, typename Enum>
inline bool AtomicLongBitFlag<N, Enum>::isOnBit(Enum bit) const {
    return getWord(bit).isBitOn(s32(bit) % BitsPerWord);
}

template <s32 N, typename Enum>
inline bool AtomicLongBitFlag<N, Enum>::isOffBit(Enum bit) const {
    return !isOnBit(bit);
}

template <s32 N, typename Enum>
inline bool AtomicLongBitFlag<N, Enum>::isZero() const {
    for (const auto& word : mStorage) {
        if (word != 0)
            return false;
    }
    return true;
}

}  // namespace ksys::util