Rework convert_integer to return result in some cases

Prefer returning the result in a std::optional<T> over returning a flag
value and taking a non-const reference to the result.
This commit is contained in:
Kp 2023-01-14 19:05:37 +00:00
parent 34046216a2
commit 99b98bb555
3 changed files with 47 additions and 37 deletions

View file

@ -12,6 +12,7 @@
#include <cstdlib>
#include <cstring>
#include <iterator>
#include <optional>
#include <type_traits>
#include "dxxsconf.h"
#include "ntstring.h"
@ -22,32 +23,45 @@ static inline bool cmp(const char *token, const char *equal, const char (&name)[
return &token[N - 1] == equal && !strncmp(token, name, N - 1);
}
template <typename F, typename T>
static inline bool convert_integer(F *f, T &t, const char *value, int base)
template <typename T>
static inline std::optional<T> convert_integer(const char *value, int base, auto libc_str_to_integer)
{
char *e;
auto r = (*f)(value, &e, base);
const auto r = libc_str_to_integer(value, &e, base);
if (*e)
/* Trailing garbage found */
return false;
T tr = static_cast<T>(r);
if (r != tr)
return std::nullopt;
if constexpr (std::is_same<T, bool>::value)
{
if (r != 0 && r != 1)
return std::nullopt;
}
else if (!std::in_range<T>(r))
/* Result truncated */
return false;
t = tr;
return true;
return std::nullopt;
return static_cast<T>(r);
}
template <typename T>
static inline typename std::enable_if<std::is_signed<T>::value, bool>::type convert_integer(T &t, const char *value, int base = 10)
requires(std::is_signed<T>::value)
static inline auto convert_integer(const char *value, int base = 10)
{
return convert_integer(strtol, t, value, base);
return convert_integer<T>(value, base, std::strtol);
}
template <typename T>
static inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type convert_integer(T &t, const char *value, int base = 10)
requires(std::is_unsigned<T>::value)
static inline auto convert_integer(const char *value, int base = 10)
{
return convert_integer(strtoul, t, value, base);
return convert_integer<T>(value, base, std::strtoul);
}
template <typename T>
requires(std::is_integral<T>::value)
static inline void convert_integer(T &t, const char *value, int base = 10)
{
if (auto r = convert_integer<T>(value, base))
t = *r;
}
template <std::size_t N>

View file

@ -171,9 +171,9 @@ int ReadConfigFile()
convert_integer(GameCfg.MusicType, value);
else if (cmp(lb, eq, CMLevelMusicPlayOrderStr))
{
unsigned CMLevelMusicPlayOrder;
if (convert_integer(CMLevelMusicPlayOrder, value) && CMLevelMusicPlayOrder <= static_cast<unsigned>(LevelMusicPlayOrder::Random))
CGameCfg.CMLevelMusicPlayOrder = static_cast<LevelMusicPlayOrder>(CMLevelMusicPlayOrder);
if (auto r = convert_integer<uint8_t>(value))
if (auto CMLevelMusicPlayOrder = *r; CMLevelMusicPlayOrder <= static_cast<uint8_t>(LevelMusicPlayOrder::Random))
CGameCfg.CMLevelMusicPlayOrder = LevelMusicPlayOrder{CMLevelMusicPlayOrder};
}
else if (cmp(lb, eq, CMLevelMusicTrack0Str))
convert_integer(CGameCfg.CMLevelMusicTrack[0], value);
@ -212,10 +212,9 @@ int ReadConfigFile()
convert_integer(CGameCfg.WindowMode, value);
else if (cmp(lb, eq, TexFiltStr))
{
uint8_t TexFilt;
if (convert_integer(TexFilt, value))
if (auto r = convert_integer<uint8_t>(value))
{
switch (TexFilt)
switch (const auto TexFilt = *r)
{
case static_cast<unsigned>(opengl_texture_filter::classic):
case static_cast<unsigned>(opengl_texture_filter::upscale):

View file

@ -1622,10 +1622,9 @@ static int get_lifetime_checksum (int a,int b)
template <uint_fast32_t shift, uint_fast32_t width>
static void convert_duplicate_powerup_integer(packed_netduplicate_items &d, const char *value)
{
/* Initialize 'i' to avoid bogus -Wmaybe-uninitialized at -Og on
* gcc-4.9 */
unsigned i = 0;
if (convert_integer(i, value) && !(i & ~((1 << width) - 1)))
if (auto r = convert_integer<unsigned>(value); !r)
return;
else if (const auto i = *r; !(i & ~((1 << width) - 1)))
d.set_sub_field<shift, width>(i);
}
}
@ -1658,23 +1657,23 @@ void read_netgame_profile(netgame_info *ng)
convert_string(ng->game_name, value, eol);
else if (cmp(lb, eq, GameModeStr))
{
uint8_t gamemode;
if (convert_integer(gamemode, value))
ng->gamemode = network_game_type{gamemode};
if (auto gamemode = convert_integer<uint8_t>(value))
ng->gamemode = network_game_type{*gamemode};
}
else if (cmp(lb, eq, RefusePlayersStr))
convert_integer(ng->RefusePlayers, value);
else if (cmp(lb, eq, DifficultyStr))
{
uint8_t difficulty;
if (convert_integer(difficulty, value))
ng->difficulty = cast_clamp_difficulty(difficulty);
if (auto difficulty = convert_integer<uint8_t>(value))
ng->difficulty = cast_clamp_difficulty(*difficulty);
}
else if (cmp(lb, eq, GameFlagsStr))
{
packed_game_flags p;
if (convert_integer(p.value, value))
if (auto r = convert_integer<uint8_t>(value))
{
const packed_game_flags p{*r};
ng->game_flag = unpack_game_flags(&p);
}
}
else if (cmp(lb, eq, AllowedItemsStr))
convert_integer(ng->AllowedItems, value);
@ -1716,9 +1715,8 @@ void read_netgame_profile(netgame_info *ng)
convert_integer(ng->KillGoal, value);
else if (cmp(lb, eq, PlayTimeAllowedStr))
{
int PlayTimeAllowed;
if (convert_integer(PlayTimeAllowed, value))
ng->PlayTimeAllowed = std::chrono::duration<int, netgame_info::play_time_allowed_abi_ratio>(PlayTimeAllowed);
if (const auto r = convert_integer<int>(value))
ng->PlayTimeAllowed = std::chrono::duration<int, netgame_info::play_time_allowed_abi_ratio>(*r);
}
else if (cmp(lb, eq, ControlInvulTimeStr))
convert_integer(ng->control_invul_time, value);
@ -1732,9 +1730,8 @@ void read_netgame_profile(netgame_info *ng)
convert_integer(ng->PitchLockFlags, value);
else if (cmp(lb, eq, AutosaveIntervalStr))
{
uint16_t AutosaveInterval;
if (convert_integer(AutosaveInterval, value))
ng->MPGameplayOptions.AutosaveInterval = std::chrono::seconds(AutosaveInterval);
if (const auto r = convert_integer<uint16_t>(value))
ng->MPGameplayOptions.AutosaveInterval = std::chrono::seconds(*r);
}
#if DXX_USE_TRACKER
else if (cmp(lb, eq, TrackerStr))