diff --git a/src/core/bitmath_func.cpp b/src/core/bitmath_func.cpp index 9b2b902b3b..ee62410291 100644 --- a/src/core/bitmath_func.cpp +++ b/src/core/bitmath_func.cpp @@ -25,18 +25,7 @@ const uint8 _ffb_64[64] = { 3, 0, 1, 0, 2, 0, 1, 0, }; -/** - * Search the first set bit in a 32 bit variable. - * - * This algorithm is a static implementation of a log - * congruence search algorithm. It checks the first half - * if there is a bit set search there further. And this - * way further. If no bit is set return 0. - * - * @param x The value to search - * @return The position of the first bit set - */ -uint8 FindFirstBit(uint32 x) +uint8 FindFirstBit32(uint32 x) { if (x == 0) return 0; /* The macro FIND_FIRST_BIT is better to use when your x is diff --git a/src/core/bitmath_func.hpp b/src/core/bitmath_func.hpp index 6fd6e29ded..0c1c5b4d33 100644 --- a/src/core/bitmath_func.hpp +++ b/src/core/bitmath_func.hpp @@ -187,21 +187,7 @@ static inline T ToggleBit(T &x, const uint8 y) #ifdef WITH_BITMATH_BUILTINS -#define FIND_FIRST_BIT(x) FindFirstBit(x) - -inline uint8 FindFirstBit(uint32 x) -{ - if (x == 0) return 0; - - return __builtin_ctz(x); -} - -inline uint8 FindFirstBit64(uint64 x) -{ - if (x == 0) return 0; - - return __builtin_ctzll(x); -} +#define FIND_FIRST_BIT(x) FindFirstBit(x) #else @@ -220,11 +206,39 @@ extern const uint8 _ffb_64[64]; */ #define FIND_FIRST_BIT(x) _ffb_64[(x)] -uint8 FindFirstBit(uint32 x); -uint8 FindFirstBit64(uint64 x); - #endif +/** + * Search the first set bit in an integer variable. + * + * @param value The value to search + * @return The position of the first bit set, or 0 when value is 0 + */ +template +static inline uint8 FindFirstBit(T value) +{ + static_assert(sizeof(T) <= sizeof(unsigned long long)); +#ifdef WITH_BITMATH_BUILTINS + if (value == 0) return 0; + typename std::make_unsigned::type unsigned_value = value; + if (sizeof(T) <= sizeof(unsigned int)) { + return __builtin_ctz(unsigned_value); + } else if (sizeof(T) == sizeof(unsigned long)) { + return __builtin_ctzl(unsigned_value); + } else { + return __builtin_ctzll(unsigned_value); + } +#else + if (sizeof(T) <= sizeof(uint32)) { + extern uint8 FindFirstBit32(x); + return FindFirstBit32(value); + } else { + extern uint8 FindFirstBit64(x); + return FindFirstBit64(value); + } +#endif +} + uint8 FindLastBit(uint64 x); /** @@ -275,6 +289,7 @@ static inline T KillFirstBit(T value) template static inline uint CountBits(T value) { + static_assert(sizeof(T) <= sizeof(unsigned long long)); #ifdef WITH_BITMATH_BUILTINS typename std::make_unsigned::type unsigned_value = value; if (sizeof(T) <= sizeof(unsigned int)) { diff --git a/src/core/pool_func.hpp b/src/core/pool_func.hpp index dbbd1254cf..c4812a9980 100644 --- a/src/core/pool_func.hpp +++ b/src/core/pool_func.hpp @@ -81,7 +81,7 @@ DEFINE_POOL_METHOD(inline size_t)::FindFirstFree() for (; bitmap_index < bitmap_end; bitmap_index++) { uint64 available = ~this->free_bitmap[bitmap_index]; if (available == 0) continue; - return (bitmap_index * 64) + FindFirstBit64(available); + return (bitmap_index * 64) + FindFirstBit(available); } if (this->first_unused < this->size) { diff --git a/src/linkgraph/refresh.cpp b/src/linkgraph/refresh.cpp index b5e288cb53..fc43277c17 100644 --- a/src/linkgraph/refresh.cpp +++ b/src/linkgraph/refresh.cpp @@ -345,7 +345,7 @@ void LinkRefresher::RefreshLinks(const Order *cur, const Order *next, uint8 flag } if (cur->IsType(OT_GOTO_STATION) || cur->IsType(OT_IMPLICIT)) { - if (cur->CanLeaveWithCargo(HasBit(flags, HAS_CARGO), FindFirstBit64(this->cargo_mask))) { + if (cur->CanLeaveWithCargo(HasBit(flags, HAS_CARGO), FindFirstBit(this->cargo_mask))) { SetBit(flags, HAS_CARGO); this->RefreshStats(cur, next); } else { diff --git a/src/order_base.h b/src/order_base.h index 4326f2e53a..9de61093f0 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -577,7 +577,7 @@ template CargoTypes FilterCargoMask(F filter_func, CargoTypes cargo template T CargoMaskValueFilter(CargoTypes &cargo_mask, F filter_func) { - CargoID first_cargo_id = FindFirstBit64(cargo_mask); + CargoID first_cargo_id = FindFirstBit(cargo_mask); T value = filter_func(first_cargo_id); CargoTypes other_cargo_mask = cargo_mask; ClrBit(other_cargo_mask, first_cargo_id); diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 5150f77c99..631e3dee0a 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -220,7 +220,7 @@ void InitRailTypes() RailTypes compatible = _railtypes[rt].all_compatible_railtypes; RailTypes to_check = compatible; while (to_check) { - RailType i = (RailType)FindFirstBit64(to_check); + RailType i = (RailType)FindFirstBit(to_check); to_check = KillFirstBit(to_check); RailTypes new_types = _railtypes[i].compatible_railtypes & (~compatible); to_check |= new_types; @@ -228,7 +228,7 @@ void InitRailTypes() } RailTypes to_update = compatible; while (to_update) { - RailType i = (RailType)FindFirstBit64(to_update); + RailType i = (RailType)FindFirstBit(to_update); to_update = KillFirstBit(to_update); _railtypes[i].all_compatible_railtypes = compatible; } diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index 9a8eac760b..e1cc7563a4 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -340,7 +340,7 @@ class NIHVehicle : public NIHelper { if (cb36_properties != UINT64_MAX) { uint64 props = cb36_properties; while (props) { - PropertyID prop = (PropertyID)FindFirstBit64(props); + PropertyID prop = (PropertyID)FindFirstBit(props); props = KillFirstBit(props); uint16 res = GetVehicleProperty(v, prop, CALLBACK_FAILED); if (res == CALLBACK_FAILED) { diff --git a/src/tracerestrict.cpp b/src/tracerestrict.cpp index 44c19e179c..37b2420602 100644 --- a/src/tracerestrict.cpp +++ b/src/tracerestrict.cpp @@ -1037,7 +1037,7 @@ void SetTraceRestrictValueDefault(TraceRestrictItem &item, TraceRestrictValueTyp case TRVT_CARGO_ID: assert(_standard_cargo_mask != 0); - SetTraceRestrictValue(item, FindFirstBit64(_standard_cargo_mask)); + SetTraceRestrictValue(item, FindFirstBit(_standard_cargo_mask)); SetTraceRestrictAuxField(item, 0); break;