mirror of https://github.com/OpenTTD/OpenTTD
Fix #13513, ec492cb267: std::numeric_limits<CompanyMask> not working causes no vehicles to exist
std::numeric_limits<T>::max() returns 0 instead of an error when the type is unknown. Solve it by implementing and using Set() and All() in BaseBitSet in same way as std::bitset.pull/13517/head
parent
521b860394
commit
37c215f1fd
|
@ -718,7 +718,7 @@ static void HandleBankruptcyTakeover(Company *c)
|
|||
}
|
||||
|
||||
/* Did we ask everyone for bankruptcy? If so, bail out. */
|
||||
if (c->bankrupt_asked == std::numeric_limits<CompanyMask>::max()) return;
|
||||
if (c->bankrupt_asked.All()) return;
|
||||
|
||||
Company *best = nullptr;
|
||||
int32_t best_performance = -1;
|
||||
|
@ -736,7 +736,7 @@ static void HandleBankruptcyTakeover(Company *c)
|
|||
|
||||
/* Asked all companies? */
|
||||
if (best_performance == -1) {
|
||||
c->bankrupt_asked = std::numeric_limits<CompanyMask>::max();
|
||||
c->bankrupt_asked.Set();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,17 +19,28 @@
|
|||
* @tparam Tvalue_type Type of values to wrap.
|
||||
* @tparam Tstorage Storage type required to hold values.
|
||||
*/
|
||||
template <typename Timpl, typename Tvalue_type, typename Tstorage>
|
||||
template <typename Timpl, typename Tvalue_type, typename Tstorage, Tstorage Tmask = std::numeric_limits<Tstorage>::max()>
|
||||
class BaseBitSet {
|
||||
public:
|
||||
using ValueType = Tvalue_type; ///< Value type of this BaseBitSet.
|
||||
using BaseType = Tstorage; ///< Storage type of this BaseBitSet, be ConvertibleThroughBase
|
||||
static constexpr Tstorage MASK = Tmask; ///< Mask of valid values.
|
||||
|
||||
constexpr BaseBitSet() : data(0) {}
|
||||
explicit constexpr BaseBitSet(Tstorage data) : data(data) {}
|
||||
explicit constexpr BaseBitSet(Tstorage data) : data(data & Tmask) {}
|
||||
|
||||
constexpr auto operator <=>(const BaseBitSet &) const noexcept = default;
|
||||
|
||||
/**
|
||||
* Set all bits.
|
||||
* @returns The bit set
|
||||
*/
|
||||
inline constexpr Timpl &Set()
|
||||
{
|
||||
this->data = Tmask;
|
||||
return static_cast<Timpl&>(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value-th bit.
|
||||
* @param value Bit to set.
|
||||
|
@ -97,6 +108,15 @@ public:
|
|||
return (this->data & other.data) == other.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if all of the values are set.
|
||||
* @returns true iff all of the values are set.
|
||||
*/
|
||||
inline constexpr bool All() const
|
||||
{
|
||||
return this->data == Tmask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if any of the given values are set.
|
||||
* @param other BitSet of values to test.
|
||||
|
@ -144,6 +164,15 @@ public:
|
|||
return this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the raw value of this bit set is valid.
|
||||
* @returns true iff the no bits outside the masked value are set.
|
||||
*/
|
||||
inline constexpr bool IsValid() const
|
||||
{
|
||||
return (this->base() & Tmask) == this->base();
|
||||
}
|
||||
|
||||
private:
|
||||
Tstorage data; ///< Bitmask of values.
|
||||
};
|
||||
|
|
|
@ -110,6 +110,12 @@ debug_inline constexpr void ToggleFlag(T &x, const T y)
|
|||
}
|
||||
}
|
||||
|
||||
/** Helper template structure to get the mask for an EnumBitSet from the end enum value. */
|
||||
template <typename Tstorage, typename Tenum, Tenum Tend_value>
|
||||
struct EnumBitSetMask {
|
||||
static constexpr Tstorage value = std::numeric_limits<Tstorage>::max() >> (std::numeric_limits<Tstorage>::digits - to_underlying(Tend_value));
|
||||
};
|
||||
|
||||
/**
|
||||
* Enum-as-bit-set wrapper.
|
||||
* Allows wrapping enum values as a bit set. Methods are loosely modelled on std::bitset.
|
||||
|
@ -119,15 +125,14 @@ debug_inline constexpr void ToggleFlag(T &x, const T y)
|
|||
* @tparam Tend_value Last valid value + 1.
|
||||
*/
|
||||
template <typename Tenum, typename Tstorage, Tenum Tend_value = Tenum{std::numeric_limits<Tstorage>::digits}>
|
||||
class EnumBitSet : public BaseBitSet<EnumBitSet<Tenum, Tstorage, Tend_value>, Tenum, Tstorage> {
|
||||
using BaseClass = BaseBitSet<EnumBitSet<Tenum, Tstorage, Tend_value>, Tenum, Tstorage>;
|
||||
class EnumBitSet : public BaseBitSet<EnumBitSet<Tenum, Tstorage, Tend_value>, Tenum, Tstorage, EnumBitSetMask<Tstorage, Tenum, Tend_value>::value> {
|
||||
using BaseClass = BaseBitSet<EnumBitSet<Tenum, Tstorage, Tend_value>, Tenum, Tstorage, EnumBitSetMask<Tstorage, Tenum, Tend_value>::value>;
|
||||
public:
|
||||
using EnumType = BaseClass::ValueType;
|
||||
static constexpr Tstorage MASK = std::numeric_limits<Tstorage>::max() >> (std::numeric_limits<Tstorage>::digits - to_underlying(Tend_value)); ///< Mask of valid values.
|
||||
|
||||
constexpr EnumBitSet() : BaseClass() {}
|
||||
constexpr EnumBitSet(Tenum value) : BaseClass() { this->Set(value); }
|
||||
explicit constexpr EnumBitSet(Tstorage data) : BaseClass(data & MASK) {}
|
||||
explicit constexpr EnumBitSet(Tstorage data) : BaseClass(data) {}
|
||||
|
||||
/**
|
||||
* Construct an EnumBitSet from a list of enum values.
|
||||
|
@ -142,15 +147,6 @@ public:
|
|||
|
||||
constexpr auto operator <=>(const EnumBitSet &) const noexcept = default;
|
||||
|
||||
/**
|
||||
* Test that the raw value of this EnumBitSet is valid.
|
||||
* @returns true iff the no bits outside the masked value are set.
|
||||
*/
|
||||
inline constexpr bool IsValid() const
|
||||
{
|
||||
return (this->base() & MASK) == this->base();
|
||||
}
|
||||
|
||||
static constexpr size_t DecayValueType(const BaseClass::ValueType &value) { return to_underlying(value); }
|
||||
};
|
||||
|
||||
|
|
|
@ -627,7 +627,7 @@ static void CompanyCheckBankrupt(Company *c)
|
|||
* is no THE-END, otherwise mark the client as spectator to make sure
|
||||
* they are no longer in control of this company. However... when you
|
||||
* join another company (cheat) the "unowned" company can bankrupt. */
|
||||
c->bankrupt_asked = std::numeric_limits<CompanyMask>::max();
|
||||
c->bankrupt_asked.Set();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -744,7 +744,7 @@ void StartupOneEngine(Engine *e, const TimerGameCalendar::YearMonthDay &aging_ym
|
|||
int intro_months = intro_ymd.year.base() * 12 + intro_ymd.month;
|
||||
if (intro_ymd.day > 1) intro_months++; // Engines are introduced at the first month start at/after intro date.
|
||||
e->age = aging_months - intro_months;
|
||||
e->company_avail = std::numeric_limits<CompanyMask>::max();
|
||||
e->company_avail.Set();
|
||||
e->flags.Set(EngineFlag::Available);
|
||||
}
|
||||
|
||||
|
@ -885,7 +885,7 @@ static void AcceptEnginePreview(EngineID eid, CompanyID company, int recursion_d
|
|||
Engine *e = Engine::Get(eid);
|
||||
|
||||
e->preview_company = INVALID_COMPANY;
|
||||
e->preview_asked = std::numeric_limits<CompanyMask>::max();
|
||||
e->preview_asked.Set();
|
||||
|
||||
EnableEngineForCompany(eid, company);
|
||||
|
||||
|
@ -980,7 +980,7 @@ static IntervalTimer<TimerGameCalendar> _calendar_engines_daily({TimerGameCalend
|
|||
e->preview_company = GetPreviewCompany(e);
|
||||
|
||||
if (e->preview_company == INVALID_COMPANY) {
|
||||
e->preview_asked = std::numeric_limits<CompanyMask>::max();
|
||||
e->preview_asked.Set();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1109,7 +1109,7 @@ static void NewVehicleAvailable(Engine *e)
|
|||
AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type);
|
||||
|
||||
/* Now available for all companies */
|
||||
e->company_avail = std::numeric_limits<CompanyMask>::max();
|
||||
e->company_avail.Set();
|
||||
|
||||
/* Do not introduce new rail wagons */
|
||||
if (IsWagon(index)) return;
|
||||
|
|
|
@ -2051,15 +2051,15 @@ bool AfterLoadGame()
|
|||
|
||||
/* More companies ... */
|
||||
for (Company *c : Company::Iterate()) {
|
||||
if (c->bankrupt_asked.base() == 0xFF) c->bankrupt_asked = std::numeric_limits<CompanyMask>::max();
|
||||
if (c->bankrupt_asked.base() == 0xFF) c->bankrupt_asked.Set();
|
||||
}
|
||||
|
||||
for (Engine *e : Engine::Iterate()) {
|
||||
if (e->company_avail.base() == 0xFF) e->company_avail = std::numeric_limits<CompanyMask>::max();
|
||||
if (e->company_avail.base() == 0xFF) e->company_avail.Set();
|
||||
}
|
||||
|
||||
for (Town *t : Town::Iterate()) {
|
||||
if (t->have_ratings.base() == 0xFF) t->have_ratings = std::numeric_limits<CompanyMask>::max();
|
||||
if (t->have_ratings.base() == 0xFF) t->have_ratings.Set();
|
||||
for (uint i = 8; i != MAX_COMPANIES; i++) t->ratings[i] = RATING_INITIAL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ struct ENGNChunkHandler : ChunkHandler {
|
|||
* Just cancel any previews. */
|
||||
e->flags.Reset(EngineFlag{4}); // ENGINE_OFFER_WINDOW_OPEN
|
||||
e->preview_company = INVALID_COMPANY;
|
||||
e->preview_asked = std::numeric_limits<CompanyMask>::max();
|
||||
e->preview_asked.Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -406,7 +406,7 @@ static bool FixTTOEngines()
|
|||
/* Make sure for example monorail and maglev are available when they should be */
|
||||
if (TimerGameCalendar::date >= e->intro_date && e->info.climates.Test(LandscapeType::Temperate)) {
|
||||
e->flags.Set(EngineFlag::Available);
|
||||
e->company_avail = std::numeric_limits<CompanyMask>::max();
|
||||
e->company_avail.Set();
|
||||
e->age = TimerGameCalendar::date > e->intro_date ? (TimerGameCalendar::date - e->intro_date).base() / 30 : 0;
|
||||
}
|
||||
} else {
|
||||
|
@ -431,7 +431,7 @@ static bool FixTTOEngines()
|
|||
* if at least one of them was available. */
|
||||
for (uint j = 0; j < lengthof(tto_to_ttd); j++) {
|
||||
if (tto_to_ttd[j] == i && _old_engines[j].company_avail.Any()) {
|
||||
e->company_avail = std::numeric_limits<CompanyMask>::max();
|
||||
e->company_avail.Set();
|
||||
e->flags.Set(EngineFlag::Available);
|
||||
break;
|
||||
}
|
||||
|
@ -441,7 +441,7 @@ static bool FixTTOEngines()
|
|||
}
|
||||
|
||||
e->preview_company = INVALID_COMPANY;
|
||||
e->preview_asked = std::numeric_limits<CompanyMask>::max();
|
||||
e->preview_asked.Set();
|
||||
e->preview_wait = 0;
|
||||
e->name = std::string{};
|
||||
}
|
||||
|
|
|
@ -724,7 +724,7 @@ protected:
|
|||
*/
|
||||
inline CompanyMask GetOverlayCompanyMask() const
|
||||
{
|
||||
return Company::IsValidID(_local_company) ? CompanyMask{}.Set(_local_company) : std::numeric_limits<CompanyMask>::max();
|
||||
return Company::IsValidID(_local_company) ? CompanyMask{}.Set(_local_company) : CompanyMask{}.Set();
|
||||
}
|
||||
|
||||
/** Blink the industries (if selected) on a regular interval. */
|
||||
|
|
Loading…
Reference in New Issue