diff --git a/common/include/partial_range.h b/common/include/partial_range.h index 5c7fd5f2e..24a1cf5a9 100644 --- a/common/include/partial_range.h +++ b/common/include/partial_range.h @@ -60,43 +60,41 @@ namespace boost struct base_partial_range_error_t : std::out_of_range { DXX_INHERIT_CONSTRUCTORS(base_partial_range_error_t, std::out_of_range); + template + __attribute_cold static std::string prepare(const char *file, unsigned line, const char *estr, const char *desc, unsigned long expr, const void *t, unsigned long d) { - char buf[256]; + char buf[(33 + (sizeof("18446744073709551615") * 2) + sizeof("0x0000000000000000") + N)]; snprintf(buf, sizeof(buf), "%s:%u: %s %lu past %p end %lu \"%s\"", file, line, desc, expr, t, d, estr); return buf; } + template + __attribute_cold + static inline std::string prepare(const char (&file)[NF], unsigned line, const char (&estr)[NE], const char (&desc)[ND], unsigned long expr, const void *t, unsigned long d) + { + return prepare<((NF + NE + ND) | (sizeof(void *) - 1)) + 1>(file + 0, line, estr, desc, expr, t, d); + } }; template struct partial_range_error_t : base_partial_range_error_t { DXX_INHERIT_CONSTRUCTORS(partial_range_error_t, base_partial_range_error_t); - static void report(const char *file, unsigned line, const char *estr, const char *desc, unsigned long expr, const T &t, unsigned long d) + template + __attribute_cold + static void report(const char (&file)[NF], unsigned line, const char (&estr)[NE], const char (&desc)[ND], unsigned long expr, const T &t, unsigned long d) { throw partial_range_error_t(base_partial_range_error_t::prepare(file, line, estr, desc, expr, addressof(t), d)); } }; -template -typename tt::enable_if::value, T &>::type partial_range(const char *, unsigned, const char *, T &, U, U = U()) = delete; - -template -static inline typename tt::enable_if::value, partial_range_t>::type partial_range(const char *, unsigned, const char *, T &t, const U &o, const U &l) __attribute_warn_unused_result; - -template -static inline typename tt::enable_if::value, partial_range_t>::type partial_range(const char *file, unsigned line, const char *estr, T &t, const U &uo, const U &ul) +template +static void check_partial_range(const char (&file)[NF], unsigned line, const char (&estr)[NE], T &t, I range_begin, I container_end, const std::size_t o, const std::size_t l) { - using std::advance; using std::distance; - auto range_begin = begin(t); - auto range_end = range_begin; - size_t o = uo, l = ul; #ifdef DXX_HAVE_BUILTIN_CONSTANT_P #define PARTIAL_RANGE_COMPILE_CHECK_BOUND(EXPR,S) \ (__builtin_constant_p(EXPR) && __builtin_constant_p(d) && (DXX_ALWAYS_ERROR_FUNCTION(partial_range_will_always_throw, S " will always throw"), 0)) - if (__builtin_constant_p(!(o < l)) && !(o < l)) - DXX_ALWAYS_ERROR_FUNCTION(partial_range_is_always_empty, "offset never less than length"); #else #define PARTIAL_RANGE_COMPILE_CHECK_BOUND(EXPR,S) 0 #endif @@ -104,26 +102,64 @@ static inline typename tt::enable_if::value, partial_range_t< if (EXPR > d) \ ((void)(PARTIAL_RANGE_COMPILE_CHECK_BOUND(EXPR,S))), \ partial_range_error_t::report(file, line, estr, S, EXPR, t, d) - size_t d = distance(range_begin, end(t)); + size_t d = distance(range_begin, container_end); PARTIAL_RANGE_CHECK_BOUND(o, "begin"); PARTIAL_RANGE_CHECK_BOUND(l, "end"); #undef PARTIAL_RANGE_CHECK_BOUND #undef PARTIAL_RANGE_COMPILE_CHECK_BOUND +} + +template +__attribute_warn_unused_result +static inline partial_range_t unchecked_partial_range(I range_begin, const std::size_t o, const std::size_t l, tt::true_type) +{ +#ifdef DXX_HAVE_BUILTIN_CONSTANT_P + if (__builtin_constant_p(!(o < l)) && !(o < l)) + DXX_ALWAYS_ERROR_FUNCTION(partial_range_is_always_empty, "offset never less than length"); +#endif + auto range_end = range_begin; if (o <= l) { + using std::advance; advance(range_begin, o); advance(range_end, l); } return {range_begin, range_end}; } -template -static inline typename tt::enable_if::value, partial_range_t>::type partial_range(const char *, unsigned, const char *, T &t, const U &l) __attribute_warn_unused_result; +template +static inline partial_range_t unchecked_partial_range(I, std::size_t, std::size_t, tt::false_type) = delete; -template -static inline typename tt::enable_if::value, partial_range_t>::type partial_range(const char *file, unsigned line, const char *estr, T &t, const U &l) +template +__attribute_warn_unused_result +static inline partial_range_t unchecked_partial_range(I range_begin, const UO &o, const UL &l) { - return partial_range(file, line, estr, t, static_cast(0), l); + /* Require unsigned length */ + typedef typename tt::conditional::value, tt::is_unsigned
    , tt::false_type>::type enable_type; + return unchecked_partial_range(range_begin, o, l, enable_type()); +} + +template +__attribute_warn_unused_result +static inline partial_range_t unchecked_partial_range(I range_begin, const UL &l) +{ + return unchecked_partial_range(range_begin, 0, l); +} + +template (nullptr)))> +__attribute_warn_unused_result +static inline partial_range_t partial_range(const char (&file)[NF], unsigned line, const char (&estr)[NE], T &t, const UO &o, const UL &l) +{ + auto range_begin = begin(t); + check_partial_range(file, line, estr, t, range_begin, end(t), o, l); + return unchecked_partial_range(range_begin, o, l); +} + +template (nullptr)))> +__attribute_warn_unused_result +static inline partial_range_t partial_range(const char (&file)[NF], unsigned line, const char (&estr)[NE], T &t, const UL &l) +{ + return partial_range(file, line, estr, t, 0, l); } #define partial_range(T,...) partial_range(__FILE__, __LINE__, #T, T, ##__VA_ARGS__) diff --git a/similar/main/mission.cpp b/similar/main/mission.cpp index 0c90f4a1b..f8bd01755 100644 --- a/similar/main/mission.cpp +++ b/similar/main/mission.cpp @@ -833,18 +833,17 @@ static int load_mission(const mle *mission) else if (istok(buf,"num_levels")) { if ((v=get_value(buf))!=NULL) { - int n_levels; - - n_levels = atoi(v); - + char *ip; + unsigned long n_levels = strtoul(v, &ip, 10); Assert(n_levels <= MAX_LEVELS_PER_MISSION); - n_levels = min(n_levels, MAX_LEVELS_PER_MISSION); - + n_levels = min(n_levels, *ip ? 0ul : MAX_LEVELS_PER_MISSION); Level_names = make_unique(n_levels); - for (int i=0;i{pointnumlist, pointnumlist + nv})) + range_for (auto pnum, unchecked_partial_range(pointnumlist, nv)) { auto &pnt = Segment_points[pnum]; if (pnt.p3_last_generation != s_current_generation)