2021-03-21 21:32:26 +00:00
|
|
|
/*
|
2024-06-15 15:01:19 +00:00
|
|
|
Copyright 2016-2024 melonDS team, RSDuck
|
2021-03-21 21:32:26 +00:00
|
|
|
|
|
|
|
This file is part of melonDS.
|
|
|
|
|
|
|
|
melonDS is free software: you can redistribute it and/or modify it under
|
|
|
|
the terms of the GNU General Public License as published by the Free
|
|
|
|
Software Foundation, either version 3 of the License, or (at your option)
|
|
|
|
any later version.
|
|
|
|
|
|
|
|
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
|
|
with melonDS. If not, see http://www.gnu.org/licenses/.
|
|
|
|
*/
|
|
|
|
|
2020-11-30 15:58:52 +00:00
|
|
|
#ifndef NONSTUPIDBITFIELD_H
|
|
|
|
#define NONSTUPIDBITFIELD_H
|
|
|
|
|
|
|
|
#include "types.h"
|
|
|
|
|
|
|
|
#include <memory.h>
|
|
|
|
|
|
|
|
#include <initializer_list>
|
|
|
|
#include <algorithm>
|
|
|
|
|
2024-05-13 15:17:39 +00:00
|
|
|
namespace melonDS
|
|
|
|
{
|
|
|
|
|
|
|
|
inline u64 GetRangedBitMask(u32 idx, u32 startBit, u32 bitsCount)
|
|
|
|
{
|
|
|
|
u32 startEntry = startBit >> 6;
|
|
|
|
u64 entriesCount = ((startBit + bitsCount + 0x3F) >> 6) - startEntry;
|
|
|
|
|
|
|
|
if (entriesCount > 1)
|
|
|
|
{
|
|
|
|
if (idx == startEntry)
|
|
|
|
return 0xFFFFFFFFFFFFFFFF << (startBit & 0x3F);
|
|
|
|
if (((startBit + bitsCount) & 0x3F) && idx == startEntry + entriesCount - 1)
|
|
|
|
return ~(0xFFFFFFFFFFFFFFFF << ((startBit + bitsCount) & 0x3F));
|
|
|
|
|
|
|
|
return 0xFFFFFFFFFFFFFFFF;
|
|
|
|
}
|
|
|
|
else if (idx == startEntry)
|
|
|
|
{
|
|
|
|
return bitsCount == 64
|
|
|
|
? 0xFFFFFFFFFFFFFFFF
|
|
|
|
: ((1ULL << bitsCount) - 1) << (startBit & 0x3F);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-30 15:58:52 +00:00
|
|
|
// like std::bitset but less stupid and optimised for
|
|
|
|
// our use case (keeping track of memory invalidations)
|
|
|
|
|
|
|
|
template <u32 Size>
|
|
|
|
struct NonStupidBitField
|
|
|
|
{
|
2021-02-09 18:24:57 +00:00
|
|
|
static constexpr u32 DataLength = (Size + 0x3F) >> 6;
|
|
|
|
u64 Data[DataLength];
|
2020-11-30 15:58:52 +00:00
|
|
|
|
|
|
|
struct Ref
|
|
|
|
{
|
|
|
|
NonStupidBitField<Size>& BitField;
|
|
|
|
u32 Idx;
|
|
|
|
|
2023-12-12 10:07:22 +00:00
|
|
|
operator bool() const
|
2020-11-30 15:58:52 +00:00
|
|
|
{
|
2021-02-09 18:24:57 +00:00
|
|
|
return BitField.Data[Idx >> 6] & (1ULL << (Idx & 0x3F));
|
2020-11-30 15:58:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ref& operator=(bool set)
|
|
|
|
{
|
2021-02-09 18:24:57 +00:00
|
|
|
BitField.Data[Idx >> 6] &= ~(1ULL << (Idx & 0x3F));
|
|
|
|
BitField.Data[Idx >> 6] |= ((u64)set << (Idx & 0x3F));
|
2020-11-30 15:58:52 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Iterator
|
|
|
|
{
|
|
|
|
NonStupidBitField<Size>& BitField;
|
|
|
|
u32 DataIdx;
|
|
|
|
u32 BitIdx;
|
|
|
|
u64 RemainingBits;
|
|
|
|
|
2023-12-12 10:07:22 +00:00
|
|
|
u32 operator*() const { return DataIdx * 64 + BitIdx; }
|
2020-11-30 15:58:52 +00:00
|
|
|
|
2023-12-12 10:07:22 +00:00
|
|
|
bool operator==(const Iterator& other) const
|
2021-02-09 18:24:57 +00:00
|
|
|
{
|
|
|
|
return other.DataIdx == DataIdx;
|
|
|
|
}
|
2023-12-12 10:07:22 +00:00
|
|
|
bool operator!=(const Iterator& other) const
|
2021-02-09 18:24:57 +00:00
|
|
|
{
|
|
|
|
return other.DataIdx != DataIdx;
|
|
|
|
}
|
2020-11-30 15:58:52 +00:00
|
|
|
|
|
|
|
void Next()
|
|
|
|
{
|
2021-02-09 18:24:57 +00:00
|
|
|
if (RemainingBits == 0)
|
2020-11-30 15:58:52 +00:00
|
|
|
{
|
2021-02-09 18:24:57 +00:00
|
|
|
for (u32 i = DataIdx + 1; i < DataLength; i++)
|
|
|
|
{
|
|
|
|
if (BitField.Data[i])
|
|
|
|
{
|
|
|
|
DataIdx = i;
|
|
|
|
RemainingBits = BitField.Data[i];
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DataIdx = DataLength;
|
|
|
|
return;
|
|
|
|
done:;
|
2020-11-30 15:58:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BitIdx = __builtin_ctzll(RemainingBits);
|
|
|
|
RemainingBits &= ~(1ULL << BitIdx);
|
2021-02-09 18:24:57 +00:00
|
|
|
|
|
|
|
if ((Size & 0x3F) && BitIdx >= Size)
|
|
|
|
DataIdx = DataLength;
|
2020-11-30 15:58:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Iterator operator++(int)
|
|
|
|
{
|
|
|
|
Iterator prev(*this);
|
|
|
|
++*this;
|
|
|
|
return prev;
|
|
|
|
}
|
|
|
|
|
|
|
|
Iterator& operator++()
|
|
|
|
{
|
2021-02-09 18:24:57 +00:00
|
|
|
Next();
|
2020-11-30 15:58:52 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-02-09 18:24:57 +00:00
|
|
|
NonStupidBitField(u32 startBit, u32 bitsCount)
|
2020-11-30 15:58:52 +00:00
|
|
|
{
|
2021-02-09 18:24:57 +00:00
|
|
|
Clear();
|
2020-11-30 15:58:52 +00:00
|
|
|
|
2021-02-09 18:24:57 +00:00
|
|
|
if (bitsCount == 0)
|
2020-11-30 15:58:52 +00:00
|
|
|
return;
|
|
|
|
|
2021-02-09 18:24:57 +00:00
|
|
|
SetRange(startBit, bitsCount);
|
|
|
|
/*for (int i = 0; i < Size; i++)
|
|
|
|
{
|
|
|
|
bool state = (*this)[i];
|
|
|
|
if (state != (i >= startBit && i < startBit + bitsCount))
|
|
|
|
{
|
|
|
|
for (u32 j = 0; j < DataLength; j++)
|
|
|
|
printf("data %016lx\n", Data[j]);
|
|
|
|
printf("blarg %d %d %d %d\n", i, startBit, bitsCount, Size);
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
}*/
|
2020-11-30 15:58:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NonStupidBitField()
|
|
|
|
{
|
2021-02-09 18:24:57 +00:00
|
|
|
Clear();
|
2020-11-30 15:58:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Iterator End()
|
|
|
|
{
|
|
|
|
return Iterator{*this, DataLength, 0, 0};
|
|
|
|
}
|
|
|
|
Iterator Begin()
|
|
|
|
{
|
2021-02-09 18:24:57 +00:00
|
|
|
for (u32 i = 0; i < DataLength; i++)
|
|
|
|
{
|
2023-08-01 01:00:41 +00:00
|
|
|
if (Data[i])
|
2021-02-09 18:24:57 +00:00
|
|
|
{
|
2023-08-01 01:00:41 +00:00
|
|
|
u32 idx = __builtin_ctzll(Data[i]);
|
|
|
|
if (idx + i * 64 < Size)
|
|
|
|
return {*this, i, idx, Data[i] & ~(1ULL << idx)};
|
2021-02-09 18:24:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return End();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Clear()
|
|
|
|
{
|
|
|
|
memset(Data, 0, sizeof(Data));
|
2020-11-30 15:58:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ref operator[](u32 idx)
|
|
|
|
{
|
|
|
|
return Ref{*this, idx};
|
|
|
|
}
|
|
|
|
|
2024-05-13 15:17:39 +00:00
|
|
|
bool operator[](u32 idx) const
|
|
|
|
{
|
|
|
|
return Data[idx >> 6] & (1ULL << (idx & 0x3F));
|
|
|
|
}
|
|
|
|
|
2021-02-09 18:24:57 +00:00
|
|
|
void SetRange(u32 startBit, u32 bitsCount)
|
|
|
|
{
|
|
|
|
u32 startEntry = startBit >> 6;
|
2021-05-03 12:36:21 +00:00
|
|
|
u64 entriesCount = (((startBit + bitsCount + 0x3F) & ~0x3F) >> 6) - startEntry;
|
2021-02-09 18:24:57 +00:00
|
|
|
|
|
|
|
if (entriesCount > 1)
|
|
|
|
{
|
|
|
|
Data[startEntry] |= 0xFFFFFFFFFFFFFFFF << (startBit & 0x3F);
|
|
|
|
if ((startBit + bitsCount) & 0x3F)
|
|
|
|
Data[startEntry + entriesCount - 1] |= ~(0xFFFFFFFFFFFFFFFF << ((startBit + bitsCount) & 0x3F));
|
|
|
|
else
|
|
|
|
Data[startEntry + entriesCount - 1] = 0xFFFFFFFFFFFFFFFF;
|
2021-05-03 12:36:21 +00:00
|
|
|
for (u64 i = startEntry + 1; i < startEntry + entriesCount - 1; i++)
|
2021-02-09 18:24:57 +00:00
|
|
|
Data[i] = 0xFFFFFFFFFFFFFFFF;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Data[startEntry] |= ((1ULL << bitsCount) - 1) << (startBit & 0x3F);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-13 15:17:39 +00:00
|
|
|
int Min() const
|
|
|
|
{
|
|
|
|
for (int i = 0; i < DataLength; i++)
|
|
|
|
{
|
|
|
|
if (Data[i])
|
|
|
|
return i * 64 + __builtin_ctzll(Data[i]);
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Max() const
|
|
|
|
{
|
|
|
|
for (int i = DataLength - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
if (Data[i])
|
|
|
|
return i * 64 + (63 - __builtin_clzll(Data[i]));
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-11-30 15:58:52 +00:00
|
|
|
NonStupidBitField& operator|=(const NonStupidBitField<Size>& other)
|
|
|
|
{
|
|
|
|
for (u32 i = 0; i < DataLength; i++)
|
|
|
|
{
|
|
|
|
Data[i] |= other.Data[i];
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
2024-05-13 15:17:39 +00:00
|
|
|
|
2020-11-30 15:58:52 +00:00
|
|
|
NonStupidBitField& operator&=(const NonStupidBitField<Size>& other)
|
|
|
|
{
|
|
|
|
for (u32 i = 0; i < DataLength; i++)
|
|
|
|
{
|
|
|
|
Data[i] &= other.Data[i];
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
2024-05-13 15:17:39 +00:00
|
|
|
|
|
|
|
operator bool() const
|
|
|
|
{
|
|
|
|
for (int i = 0; i < DataLength - 1; i++)
|
|
|
|
{
|
|
|
|
if (Data[i])
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (Data[DataLength-1] & ((Size&0x3F) ? ~(0xFFFFFFFFFFFFFFFF << (Size&0x3F)) : 0xFFFFFFFFFFFFFFFF))
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2020-11-30 15:58:52 +00:00
|
|
|
};
|
|
|
|
|
2023-11-25 17:32:09 +00:00
|
|
|
}
|
2020-11-30 15:58:52 +00:00
|
|
|
|
2021-05-03 12:36:21 +00:00
|
|
|
#endif
|