Implement custom BitSet and replace std::bitset

This commit is contained in:
ζeh Matt 2021-12-12 23:16:17 +02:00
parent f55bc799cc
commit 16635b9192
No known key found for this signature in database
GPG Key ID: 18CE582C71A225B0
11 changed files with 548 additions and 22 deletions

View File

@ -14,10 +14,13 @@
#include <openrct2-ui/interface/Widget.h>
#include <openrct2/Context.h>
#include <openrct2/Input.h>
#include <openrct2/core/BitSet.hpp>
#include <openrct2/drawing/Drawing.h>
#include <openrct2/localisation/Localisation.h>
#include <openrct2/sprites.h>
using namespace OpenRCT2;
// The maximum number of rows to list before items overflow into new columns
constexpr int32_t DROPDOWN_TEXT_MAX_ROWS = 32;
@ -47,8 +50,8 @@ int32_t gDropdownNumItems;
rct_string_id gDropdownItemsFormat[Dropdown::ItemsMaxSize];
int64_t gDropdownItemsArgs[Dropdown::ItemsMaxSize];
static ImageId _dropdownItemsImages[Dropdown::ItemsMaxSize];
static std::bitset<Dropdown::ItemsMaxSize> _dropdownItemsChecked = {};
static std::bitset<Dropdown::ItemsMaxSize> _dropdownItemsDisabled = {};
static BitSet<Dropdown::ItemsMaxSize> _dropdownItemsChecked = {};
static BitSet<Dropdown::ItemsMaxSize> _dropdownItemsDisabled = {};
bool gDropdownIsColour;
int32_t gDropdownLastColourHover;
int32_t gDropdownHighlightedIndex;

View File

@ -13,12 +13,15 @@
#include <openrct2-ui/windows/Window.h>
#include <openrct2/Game.h>
#include <openrct2/actions/ParkMarketingAction.h>
#include <openrct2/core/BitSet.hpp>
#include <openrct2/drawing/Drawing.h>
#include <openrct2/localisation/Localisation.h>
#include <openrct2/ride/Ride.h>
#include <openrct2/ride/RideData.h>
#include <openrct2/ride/ShopItem.h>
using namespace OpenRCT2;
static constexpr const rct_string_id WINDOW_TITLE = STR_NONE;
static constexpr const int32_t WH = 109;
static constexpr const int32_t WW = 350;
@ -95,7 +98,7 @@ private:
*/
void GetShopItems()
{
std::bitset<EnumValue(ShopItem::Count)> items = {};
BitSet<EnumValue(ShopItem::Count)> items = {};
for (auto& curRide : GetRideManager())
{
auto rideEntry = curRide.GetRideEntry();

View File

@ -0,0 +1,514 @@
/*****************************************************************************
* Copyright (c) 2014-2021 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#pragma once
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <string>
namespace OpenRCT2
{
namespace Detail
{
namespace BitSet
{
static constexpr size_t byte_bits = std::numeric_limits<std::underlying_type_t<std::byte>>::digits;
static constexpr size_t round_bits(size_t v)
{
const auto reminder = v % byte_bits;
if (reminder == 0u)
return v;
return v + (byte_bits - (v % byte_bits));
}
#ifdef _DEBUG
static_assert(round_bits(1) == 8);
static_assert(round_bits(4) == 8);
static_assert(round_bits(8) == 8);
static_assert(round_bits(9) == 16);
#endif
// Returns the amount of bytes required for a single block.
static constexpr size_t storage_byte_size(size_t numBits)
{
numBits = round_bits(numBits);
if (numBits >= std::numeric_limits<uintptr_t>::digits)
return sizeof(uintptr_t);
const auto numBytes = numBits / byte_bits;
auto mask = 1u;
while (mask < numBytes)
{
mask <<= 1u;
}
return mask;
}
// TODO: Replace with std::popcount when C++20 is enabled.
template<typename T> static constexpr size_t popcount(const T val)
{
size_t res = 0;
auto x = static_cast<std::make_unsigned_t<T>>(val);
while (x > 0u)
{
if (x & 1u)
res++;
x >>= 1u;
}
return res;
}
#ifdef _DEBUG
static_assert(storage_byte_size(1) == 1);
static_assert(storage_byte_size(4) == 1);
static_assert(storage_byte_size(8) == 1);
static_assert(storage_byte_size(9) == 2);
#endif
template<size_t TByteSize> struct storage_block_type;
template<> struct storage_block_type<1>
{
using value_type = uint8_t;
};
template<> struct storage_block_type<2>
{
using value_type = uint16_t;
};
template<> struct storage_block_type<4>
{
using value_type = uint32_t;
};
template<> struct storage_block_type<8>
{
using value_type = uint64_t;
};
template<size_t TBitSize> struct storage_block_type_aligned
{
using value_type = typename storage_block_type<storage_byte_size(TBitSize)>::value_type;
};
} // namespace BitSet
} // namespace Detail
template<uint32_t TBitSize> class BitSet
{
public:
static constexpr size_t storage_capacity_bits = Detail::BitSet::round_bits(TBitSize);
static constexpr size_t storage_capacity_bytes = storage_capacity_bits / Detail::BitSet::byte_bits;
using storage_block_type = typename Detail::BitSet::storage_block_type_aligned<storage_capacity_bits>::value_type;
static constexpr storage_block_type value_zero = storage_block_type{ 0u };
static constexpr storage_block_type value_one = storage_block_type{ 1u };
static constexpr size_t block_type_bit_size = sizeof(storage_block_type) * Detail::BitSet::byte_bits;
static constexpr size_t block_count = storage_capacity_bits / block_type_bit_size;
static constexpr storage_block_type block_init_value{};
static constexpr storage_block_type block_mask_value = ~block_init_value;
static constexpr bool requires_trim = TBitSize != storage_capacity_bits;
using storage_data = std::array<storage_block_type, block_count>;
// Proxy object to access the bits as single value.
template<typename T> class reference_base
{
T& storage_;
const size_t blockIndex_;
const size_t blockOffset_;
public:
constexpr reference_base(T& data, size_t blockIndex, size_t blockOffset) noexcept
: storage_(data)
, blockIndex_(blockIndex)
, blockOffset_(blockOffset)
{
}
constexpr reference_base& operator=(const bool value) noexcept
{
if (!value)
storage_[blockIndex_] &= ~(value_one << blockOffset_);
else
storage_[blockIndex_] |= (value_one << blockOffset_);
return *this;
}
constexpr reference_base& operator=(const reference_base& value) noexcept
{
return reference_base::operator=(value.value());
}
constexpr bool value() const noexcept
{
return (storage_[blockIndex_] & (value_one << blockOffset_)) != value_zero;
}
constexpr operator bool() const noexcept
{
return value();
}
};
using reference = reference_base<storage_data>;
using const_reference = reference_base<const storage_data>;
template<typename T, typename TValue> class iterator_base
{
T* _bitset{};
size_t _pos{};
public:
constexpr iterator_base() = default;
constexpr iterator_base(T* bset, size_t pos)
: _bitset(bset)
, _pos(pos)
{
}
constexpr auto operator*() const
{
const auto blockIndex = compute_block_index(_pos);
const auto blockOffset = compute_block_offset(_pos);
return TValue(_bitset->data(), blockIndex, blockOffset);
}
constexpr bool operator==(iterator_base other) const
{
return _bitset == other._bitset && _pos == other._pos;
}
constexpr bool operator!=(iterator_base other) const
{
return !(*this == other);
}
constexpr iterator_base& operator++()
{
_pos++;
return *this;
}
constexpr iterator_base operator++(int)
{
iterator_base res = *this;
++(*this);
return res;
}
constexpr iterator_base& operator--()
{
_pos--;
return *this;
}
constexpr iterator_base operator--(int)
{
iterator_base res = *this;
--(*this);
return res;
}
public:
using difference_type = std::size_t;
using value_type = TValue;
using pointer = const TValue*;
using reference = const TValue&;
using iterator_category = std::forward_iterator_tag;
};
using iterator = iterator_base<BitSet, reference>;
using const_iterator = iterator_base<const BitSet, const_reference>;
private:
storage_data data_{};
public:
constexpr BitSet() = default;
constexpr BitSet(const storage_block_type val)
: data_{ val }
{
}
constexpr BitSet(const std::initializer_list<size_t>& indices)
{
for (auto idx : indices)
{
set(idx, true);
}
}
constexpr size_t size() const noexcept
{
return TBitSize;
}
constexpr size_t count() const noexcept
{
size_t numBits = 0;
for (auto& data : data_)
{
numBits += Detail::BitSet::popcount(data);
}
return numBits;
}
constexpr size_t capacity() const noexcept
{
return storage_capacity_bits;
}
constexpr storage_data& data() noexcept
{
return data_;
}
constexpr const storage_data& data() const noexcept
{
return data_;
}
constexpr BitSet& set(size_t index, bool value) noexcept
{
const auto blockIndex = compute_block_index(index);
const auto blockOffset = compute_block_offset(index);
if (!value)
data_[blockIndex] &= ~(value_one << blockOffset);
else
data_[blockIndex] |= (value_one << blockOffset);
return *this;
}
constexpr bool get(size_t index) const noexcept
{
const auto blockIndex = compute_block_index(index);
const auto blockOffset = compute_block_offset(index);
return (data_[blockIndex] & (value_one << blockOffset)) != value_zero;
}
constexpr bool operator[](const size_t index) const noexcept
{
const auto blockIndex = compute_block_index(index);
const auto blockOffset = compute_block_offset(index);
const_reference ref(data_, blockIndex, blockOffset);
return ref.value();
}
constexpr reference operator[](const size_t index) noexcept
{
const auto blockIndex = compute_block_index(index);
const auto blockOffset = compute_block_offset(index);
return reference(data_, blockIndex, blockOffset);
}
constexpr BitSet& flip() noexcept
{
for (auto& data : data_)
{
data ^= block_mask_value;
}
if constexpr (requires_trim)
{
trim();
}
return *this;
}
constexpr BitSet& reset() noexcept
{
std::fill(data_.begin(), data_.end(), block_init_value);
if constexpr (requires_trim)
{
trim();
}
return *this;
}
constexpr const_iterator begin() const noexcept
{
return const_iterator(this, 0);
}
constexpr const_iterator end() const noexcept
{
return const_iterator(this, size());
}
constexpr iterator begin() noexcept
{
return iterator(this, 0);
}
constexpr iterator end() noexcept
{
return iterator(this, size());
}
template<class TChar = char, class TTraits = std::char_traits<TChar>, class TAlloc = std::allocator<TChar>>
std::basic_string<TChar, TTraits, TAlloc> to_string(TChar zero = TChar{ '0' }, TChar one = TChar{ '1' }) const
{
std::basic_string<TChar, TTraits, TAlloc> res;
res.resize(TBitSize);
for (size_t i = 0; i < TBitSize; ++i)
{
// Printed as little-endian.
res[TBitSize - i - 1] = get(i) ? one : zero;
}
return res;
}
constexpr BitSet operator^(const BitSet& other) const noexcept
{
BitSet res = *this;
for (size_t i = 0; i < data_.size(); i++)
{
res.data_[i] ^= other.data_[i];
}
if constexpr (requires_trim)
{
res.trim();
}
return res;
}
constexpr BitSet& operator^=(const BitSet& other) noexcept
{
*this = *this ^ other;
return *this;
}
constexpr BitSet operator|(const BitSet& other) const noexcept
{
BitSet res = *this;
for (size_t i = 0; i < data_.size(); i++)
{
res.data_[i] |= other.data_[i];
}
if constexpr (requires_trim)
{
res.trim();
}
return res;
}
constexpr BitSet& operator|=(const BitSet& other) noexcept
{
*this = *this | other;
return *this;
}
constexpr BitSet operator&(const BitSet& other) const noexcept
{
BitSet res = *this;
for (size_t i = 0; i < data_.size(); i++)
{
res.data_[i] &= other.data_[i];
}
if constexpr (requires_trim)
{
res.trim();
}
return res;
}
constexpr BitSet& operator&=(const BitSet& other) noexcept
{
*this = *this & other;
return *this;
}
constexpr BitSet operator~() const noexcept
{
BitSet res = *this;
for (size_t i = 0; i < data_.size(); i++)
{
res.data_[i] = ~res.data_[i];
}
if constexpr (requires_trim)
{
res.trim();
}
return res;
}
constexpr bool operator<(const BitSet& other) const noexcept
{
return std::lexicographical_compare(data_.begin(), data_.end(), other.data_.begin(), other.data_.end(), std::less);
}
constexpr bool operator<=(const BitSet& other) const noexcept
{
return std::lexicographical_compare(
data_.begin(), data_.end(), other.data_.begin(), other.data_.end(), std::less_equal);
}
constexpr bool operator>(const BitSet& other) const noexcept
{
return std::lexicographical_compare(
data_.begin(), data_.end(), other.data_.begin(), other.data_.end(), std::greater);
}
constexpr bool operator>=(const BitSet& other) const noexcept
{
return std::lexicographical_compare(
data_.begin(), data_.end(), other.data_.begin(), other.data_.end(), std::greater_equal);
}
private:
static constexpr size_t compute_block_index(size_t idx) noexcept
{
if constexpr (block_count == 1)
{
return 0;
}
else
{
return idx / block_type_bit_size;
}
}
static constexpr size_t compute_block_offset(size_t idx) noexcept
{
if constexpr (block_count == 1)
{
return idx;
}
else
{
return idx % block_type_bit_size;
}
}
// Some operations require to trim of the excess.
constexpr void trim() noexcept
{
const auto byteIdx = TBitSize / block_type_bit_size;
const auto bitIdx = TBitSize % block_type_bit_size;
if constexpr (bitIdx == 0)
return;
auto trimMask = block_mask_value;
trimMask <<= (block_type_bit_size - bitIdx);
trimMask >>= (block_type_bit_size - bitIdx);
data_[byteIdx] &= trimMask;
}
};
} // namespace OpenRCT2

View File

@ -1854,9 +1854,9 @@ Ride* Guest::FindBestRideToGoOn()
return mostExcitingRide;
}
std::bitset<MAX_RIDES> Guest::FindRidesToGoOn()
BitSet<MAX_RIDES> Guest::FindRidesToGoOn()
{
std::bitset<MAX_RIDES> rideConsideration;
BitSet<MAX_RIDES> rideConsideration;
// FIX Originally checked for a toy, likely a mistake and should be a map,
// but then again this seems to only allow the peep to go on
@ -3111,7 +3111,7 @@ template<typename T> static void peep_head_for_nearest_ride(Guest* peep, bool co
}
}
std::bitset<MAX_RIDES> rideConsideration;
BitSet<MAX_RIDES> rideConsideration;
if (!considerOnlyCloseRides && (peep->HasItem(ShopItem::Map)))
{
// Consider all rides in the park

View File

@ -9,13 +9,12 @@
#pragma once
#include "../core/BitSet.hpp"
#include "../management/Finance.h"
#include "../ride/Ride.h"
#include "../ride/ShopItem.h"
#include "Peep.h"
#include <bitset>
#define PEEP_MAX_THOUGHTS 5
#define PEEP_HUNGER_WARNING_THRESHOLD 25
@ -33,6 +32,8 @@
#define PEEP_MAX_NAUSEA 255
#define PEEP_MAX_THIRST 255
using namespace OpenRCT2;
enum class PeepThoughtType : uint8_t
{
CantAffordRide = 0, // "I can't afford"
@ -419,7 +420,7 @@ private:
void MakePassingPeepsSick(Guest* passingPeep);
void GivePassingPeepsIceCream(Guest* passingPeep);
Ride* FindBestRideToGoOn();
std::bitset<MAX_RIDES> FindRidesToGoOn();
BitSet<MAX_RIDES> FindRidesToGoOn();
bool FindVehicleToEnter(Ride* ride, std::vector<uint8_t>& car_array);
void GoToRideEntrance(Ride* ride);
};

View File

@ -149,6 +149,7 @@
<ClInclude Include="config\IniReader.hpp" />
<ClInclude Include="config\IniWriter.hpp" />
<ClInclude Include="Context.h" />
<ClInclude Include="core\BitSet.hpp" />
<ClInclude Include="core\ChecksumStream.h" />
<ClInclude Include="core\CircularBuffer.h" />
<ClInclude Include="core\Collections.hpp" />
@ -942,4 +943,4 @@
<ClCompile Include="world\Wall.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
</Project>

View File

@ -13,6 +13,7 @@
#include "../OpenRCT2.h"
#include "../actions/ParkSetResearchFundingAction.h"
#include "../config/Config.h"
#include "../core/BitSet.hpp"
#include "../core/Guard.hpp"
#include "../core/Memory.hpp"
#include "../interface/Window.h"
@ -36,6 +37,8 @@
#include <algorithm>
#include <iterator>
using namespace OpenRCT2;
static constexpr const int32_t _researchRate[] = {
0,
160,
@ -966,7 +969,7 @@ bool ResearchItem::operator==(const ResearchItem& rhs) const
return (entryIndex == rhs.entryIndex && baseRideType == rhs.baseRideType && type == rhs.type);
}
static std::bitset<RIDE_TYPE_COUNT> _seenRideType = {};
static BitSet<RIDE_TYPE_COUNT> _seenRideType = {};
static void research_update_first_of_type(ResearchItem* researchItem)
{

View File

@ -1936,7 +1936,7 @@ static void get_ride_queue_end(TileCoordsXYZ& loc)
* appropriate.
*/
static StationIndex guest_pathfinding_select_random_station(
const Guest* guest, int32_t numEntranceStations, std::bitset<MAX_STATIONS>& entranceStations)
const Guest* guest, int32_t numEntranceStations, BitSet<MAX_STATIONS>& entranceStations)
{
int32_t select = guest->GuestNumRides % numEntranceStations;
while (select > 0)
@ -2174,7 +2174,7 @@ int32_t guest_path_finding(Guest* peep)
StationIndex closestStationNum = 0;
int32_t numEntranceStations = 0;
std::bitset<MAX_STATIONS> entranceStations = {};
BitSet<MAX_STATIONS> entranceStations = {};
for (StationIndex stationNum = 0; stationNum < MAX_STATIONS; ++stationNum)
{

View File

@ -15,6 +15,7 @@
#include "../ParkImporter.h"
#include "../actions/WallPlaceAction.h"
#include "../audio/audio.h"
#include "../core/BitSet.hpp"
#include "../core/Collections.hpp"
#include "../core/Console.hpp"
#include "../core/FileStream.h"
@ -119,8 +120,8 @@ namespace RCT1
ObjectEntryIndex _footpathRailingsTypeToEntryMap[4]{};
// Research
std::bitset<MAX_RIDE_OBJECTS> _researchRideEntryUsed{};
std::bitset<EnumValue(RideType::Count)> _researchRideTypeUsed{};
BitSet<MAX_RIDE_OBJECTS> _researchRideEntryUsed{};
BitSet<EnumValue(RideType::Count)> _researchRideTypeUsed{};
// Scenario repository - used for determining scenario name
IScenarioRepository* _scenarioRepository = GetScenarioRepository();
@ -422,7 +423,7 @@ namespace RCT1
{
size_t researchListCount;
const ResearchItem* researchList = GetResearchList(&researchListCount);
std::bitset<EnumValue(RideType::Count)> rideTypeInResearch = GetRideTypesPresentInResearchList(
BitSet<EnumValue(RideType::Count)> rideTypeInResearch = GetRideTypesPresentInResearchList(
researchList, researchListCount);
for (size_t i = 0; i < researchListCount; i++)
{
@ -2052,10 +2053,10 @@ namespace RCT1
}
}
static std::bitset<EnumValue(RideType::Count)> GetRideTypesPresentInResearchList(
static BitSet<EnumValue(RideType::Count)> GetRideTypesPresentInResearchList(
const RCT1::ResearchItem* researchList, size_t researchListCount)
{
std::bitset<EnumValue(RideType::Count)> ret = {};
BitSet<EnumValue(RideType::Count)> ret = {};
for (size_t i = 0; i < researchListCount; i++)
{

View File

@ -91,7 +91,7 @@ namespace RCT2
S6Data _s6{};
uint8_t _gameVersion = 0;
bool _isSV7 = false;
std::bitset<Limits::MaxRidesInPark> _isFlatRide{};
BitSet<Limits::MaxRidesInPark> _isFlatRide{};
ObjectEntryIndex _pathToSurfaceMap[16];
ObjectEntryIndex _pathToQueueSurfaceMap[16];
ObjectEntryIndex _pathToRailingMap[16];

View File

@ -18,6 +18,7 @@
#include "../ParkImporter.h"
#include "../audio/audio.h"
#include "../config/Config.h"
#include "../core/BitSet.hpp"
#include "../core/Guard.hpp"
#include "../core/Random.hpp"
#include "../entity/Duck.h"
@ -53,7 +54,6 @@
#include "ScenarioSources.h"
#include <algorithm>
#include <bitset>
const rct_string_id ScenarioCategoryStringIds[SCENARIO_CATEGORY_COUNT] = {
STR_BEGINNER_PARKS, STR_CHALLENGING_PARKS, STR_EXPERT_PARKS, STR_REAL_PARKS, STR_OTHER_PARKS,
@ -658,7 +658,7 @@ ObjectiveStatus Objective::CheckParkValueBy() const
ObjectiveStatus Objective::Check10RollerCoasters() const
{
auto rcs = 0;
std::bitset<MAX_RIDE_OBJECTS> type_already_counted;
BitSet<MAX_RIDE_OBJECTS> type_already_counted;
for (const auto& ride : GetRideManager())
{
if (ride.status == RideStatus::Open && ride.excitement >= RIDE_RATING(6, 00) && ride.subtype != OBJECT_ENTRY_INDEX_NULL)
@ -757,7 +757,7 @@ ObjectiveStatus Objective::CheckMonthlyRideIncome() const
*/
ObjectiveStatus Objective::Check10RollerCoastersLength() const
{
std::bitset<MAX_RIDE_OBJECTS> type_already_counted;
BitSet<MAX_RIDE_OBJECTS> type_already_counted;
auto rcs = 0;
for (const auto& ride : GetRideManager())
{