mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 08:33:12 -05:00
Both parse like strtol and strtoll in base 10. The guest long is 64 bits wide on every host, so atol uses strtoll rather than the host atol, whose long is 32 bits on Windows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
279 lines
14 KiB
C++
279 lines
14 KiB
C++
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include <bit>
|
|
#include <cfenv>
|
|
#include <cmath>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <limits>
|
|
#include <initializer_list>
|
|
extern "C" {
|
|
double APS5_VABI atof_nid_postfix(const char*);
|
|
float APS5_VABI strtof_nid_postfix(const char*, char**);
|
|
long double APS5_VABI strtold_nid_postfix(const char*, char**);
|
|
std::int64_t APS5_VABI strtol_nid_postfix(const char*, char**, int);
|
|
std::uint64_t APS5_VABI strtoul_nid_postfix(const char*, char**, int);
|
|
std::intmax_t APS5_VABI strtoimax_nid_postfix(const char*, char**, int);
|
|
long long APS5_VABI strtoll_nid_postfix(const char*, char**, int);
|
|
unsigned long long APS5_VABI strtoull_nid_postfix(const char*, char**, int);
|
|
std::uintmax_t APS5_VABI strtoumax_nid_postfix(const char*, char**, int);
|
|
unsigned long long APS5_VABI _Stoull_nid_postfix(const char*, char**, int);
|
|
std::uint64_t APS5_VABI _Stoul_nid_postfix(const char*, char**, int);
|
|
std::int64_t APS5_VABI atol_nid_postfix(const char*);
|
|
long long APS5_VABI atoll_nid_postfix(const char*);
|
|
int* APS5_VABI __error_nid_postfix();
|
|
struct LibcFloatConstant { std::uint32_t bits[4]; };
|
|
extern LibcFloatConstant _FInf_nid_postfix;
|
|
extern LibcFloatConstant _FNan_nid_postfix;
|
|
short APS5_VABI _FDtest_nid_postfix(const float*);
|
|
int APS5_VABI __fpclassifyf_nid_postfix(float);
|
|
float APS5_VABI fmodf_nid_postfix(float, float);
|
|
float APS5_VABI asinf_nid_postfix(float);
|
|
float APS5_VABI acosf_nid_postfix(float);
|
|
float APS5_VABI atan2f_nid_postfix(float, float);
|
|
float APS5_VABI hypotf_nid_postfix(float, float);
|
|
double APS5_VABI hypot_nid_postfix(double, double);
|
|
float APS5_VABI tanf_nid_postfix(float);
|
|
float APS5_VABI log10f_nid_postfix(float);
|
|
float APS5_VABI logbf_nid_postfix(float);
|
|
double APS5_VABI exp2_nid_postfix(double);
|
|
double APS5_VABI ldexp_nid_postfix(double, int);
|
|
double APS5_VABI scalbn_nid_postfix(double, int);
|
|
float APS5_VABI scalbnf_nid_postfix(float, int);
|
|
double APS5_VABI frexp_nid_postfix(double, int*);
|
|
float APS5_VABI frexpf_nid_postfix(float, int*);
|
|
std::int64_t APS5_VABI lround_nid_postfix(double);
|
|
std::div_t APS5_VABI div_nid_postfix(int, int);
|
|
std::int64_t APS5_VABI lroundf_nid_postfix(float);
|
|
std::int64_t APS5_VABI llround_nid_postfix(double);
|
|
int APS5_VABI __isfinitef_nid_postfix(float);
|
|
int APS5_VABI __isnormal_nid_postfix(double);
|
|
int APS5_VABI __isnormalf_nid_postfix(float);
|
|
int APS5_VABI __isinff_nid_postfix(float);
|
|
std::lldiv_t APS5_VABI lldiv_nid_postfix(long long, long long);
|
|
std::lldiv_t APS5_VABI ldiv_nid_postfix(std::int64_t, std::int64_t);
|
|
}
|
|
static void Require(bool value) { if (!value) std::abort(); }
|
|
|
|
static void CheckIntegerConversions() {
|
|
for (const long long numerator : {4294967301LL, -4294967301LL}) {
|
|
for (const long long denominator : {3LL, -3LL}) {
|
|
const auto result = lldiv_nid_postfix(numerator, denominator);
|
|
Require(result.quot == numerator / denominator && result.rem == numerator % denominator);
|
|
Require(result.quot * denominator + result.rem == numerator);
|
|
const auto wide = ldiv_nid_postfix(numerator, denominator);
|
|
Require(wide.quot == result.quot && wide.rem == result.rem);
|
|
}
|
|
}
|
|
const auto extreme = ldiv_nid_postfix(INT64_MIN, 2);
|
|
Require(extreme.quot == INT64_MIN / 2 && extreme.rem == 0);
|
|
struct SignedCase {
|
|
const char* text;
|
|
int base;
|
|
std::int64_t value;
|
|
std::size_t consumed;
|
|
int error;
|
|
};
|
|
const SignedCase signedCases[] = {
|
|
{"-42tail", 10, -42, 3, 0},
|
|
{"2147483648!", 10, INT64_C(2147483648), 10, 0},
|
|
{"-2147483649!", 10, -INT64_C(2147483649), 11, 0},
|
|
{"4294967296!", 10, INT64_C(4294967296), 10, 0},
|
|
{"9223372036854775807!", 10, INT64_MAX, 19, 0},
|
|
{"-9223372036854775808!", 10, INT64_MIN, 20, 0},
|
|
{"9223372036854775808!", 10, INT64_MAX, 19, 34},
|
|
{"-9223372036854775809!", 10, INT64_MIN, 20, 34},
|
|
{"18446744073709551616000!", 10, INT64_MAX, 23, 34},
|
|
{" \t+0x100000000z", 0, INT64_C(4294967296), 14, 0},
|
|
{"-0x8000000000000000!", 0, INT64_MIN, 19, 0},
|
|
{"0x8000000000000000!", 16, INT64_MAX, 18, 34},
|
|
{"0100000000000!", 0, INT64_C(8589934592), 13, 0},
|
|
{"100000000000000000000000000000000!", 2, INT64_C(4294967296), 33, 0},
|
|
{"0b101", 0, 0, 1, 0},
|
|
{"0b101", 2, 0, 1, 0},
|
|
{" -0B1!", 0, 0, 3, 0},
|
|
{"0b2", 0, 0, 1, 0},
|
|
{"0b101", 16, 0xb101, 5, 0},
|
|
{"z!", 36, 35, 1, 0},
|
|
{"", 10, 0, 0, 0},
|
|
{" \t+!", 10, 0, 0, 0},
|
|
{"123!", 10, 123, 3, 0}
|
|
};
|
|
for (const auto& test : signedCases) {
|
|
char* end = nullptr;
|
|
*__error_nid_postfix() = 0;
|
|
const auto value = strtol_nid_postfix(test.text, &end, test.base);
|
|
if (value != test.value || end != test.text + test.consumed || *__error_nid_postfix() != test.error) {
|
|
std::fprintf(stderr, "Guest strtol failed for '%s' in base %d\n", test.text, test.base);
|
|
std::abort();
|
|
}
|
|
*__error_nid_postfix() = 0;
|
|
const auto maxValue = strtoimax_nid_postfix(test.text, &end, test.base);
|
|
if (maxValue != test.value || end != test.text + test.consumed || *__error_nid_postfix() != test.error) {
|
|
std::fprintf(stderr, "Guest strtoimax failed for '%s' in base %d\n", test.text, test.base);
|
|
std::abort();
|
|
}
|
|
}
|
|
struct UnsignedCase {
|
|
const char* text;
|
|
int base;
|
|
std::uint64_t value;
|
|
std::size_t consumed;
|
|
int error;
|
|
};
|
|
const UnsignedCase unsignedCases[] = {
|
|
{"4294967296!", 10, UINT64_C(4294967296), 10, 0},
|
|
{"9223372036854775808!", 10, UINT64_C(9223372036854775808), 19, 0},
|
|
{"18446744073709551615!", 10, UINT64_MAX, 20, 0},
|
|
{"18446744073709551616!", 10, UINT64_MAX, 20, 34},
|
|
{"18446744073709551616000!", 10, UINT64_MAX, 23, 34},
|
|
{"-1!", 10, UINT64_MAX, 2, 0},
|
|
{"-4294967296!", 10, UINT64_MAX - UINT64_C(4294967295), 11, 0},
|
|
{"-18446744073709551615!", 10, 1, 21, 0},
|
|
{"-18446744073709551616!", 10, UINT64_MAX, 21, 34},
|
|
{" \t+0xffffffffffffffffz", 0, UINT64_MAX, 21, 0},
|
|
{"0x10000000000000000!", 16, UINT64_MAX, 19, 34},
|
|
{"0100000000000!", 0, UINT64_C(8589934592), 13, 0},
|
|
{"100000000000000000000000000000000!", 2, UINT64_C(4294967296), 33, 0},
|
|
{"0b101", 0, 0, 1, 0},
|
|
{"0B11", 2, 0, 1, 0},
|
|
{" +0b1!", 2, 0, 3, 0},
|
|
{"0b101", 16, 0xb101, 5, 0},
|
|
{"z!", 36, 35, 1, 0},
|
|
{"", 10, 0, 0, 0},
|
|
{" \t-!", 10, 0, 0, 0},
|
|
{"123!", 10, 123, 3, 0}
|
|
};
|
|
for (const auto& test : unsignedCases) {
|
|
char* end = nullptr;
|
|
*__error_nid_postfix() = 0;
|
|
const auto value = strtoul_nid_postfix(test.text, &end, test.base);
|
|
if (value != test.value || end != test.text + test.consumed || *__error_nid_postfix() != test.error) {
|
|
std::fprintf(stderr, "Guest strtoul failed for '%s' in base %d\n", test.text, test.base);
|
|
std::abort();
|
|
}
|
|
}
|
|
for (const int base : {0, 2}) {
|
|
const char text[] = " -0B11";
|
|
char* end = nullptr;
|
|
Require(strtoll_nid_postfix(text, &end, base) == 0 && end == text + 3);
|
|
Require(strtoull_nid_postfix(text, &end, base) == 0 && end == text + 3);
|
|
Require(strtoumax_nid_postfix(text, &end, base) == 0 && end == text + 3);
|
|
Require(_Stoull_nid_postfix(text, &end, base) == 0 && end == text + 3);
|
|
Require(_Stoul_nid_postfix(text, &end, base) == 0 && end == text + 3);
|
|
}
|
|
Require(atol_nid_postfix(" \t-4294967296tail") == -INT64_C(4294967296));
|
|
Require(atol_nid_postfix("9223372036854775807") == INT64_MAX && atol_nid_postfix("+12") == 12);
|
|
Require(atol_nid_postfix("0x10") == 0 && atol_nid_postfix("010") == 10 && atol_nid_postfix("") == 0);
|
|
Require(atoll_nid_postfix("-9223372036854775808") == INT64_MIN && atoll_nid_postfix("4294967297x") == 4294967297LL);
|
|
Require(atoll_nid_postfix(" -0012") == -12 && atoll_nid_postfix("z1") == 0);
|
|
*__error_nid_postfix() = 13;
|
|
Require(strtol_nid_postfix("-4294967296", nullptr, 10) == -INT64_C(4294967296));
|
|
Require(*__error_nid_postfix() == 13);
|
|
Require(strtoul_nid_postfix("4294967296", nullptr, 10) == UINT64_C(4294967296));
|
|
Require(*__error_nid_postfix() == 13);
|
|
Require(_Stoul_nid_postfix("4294967296", nullptr, 10) == UINT64_C(4294967296));
|
|
Require(*__error_nid_postfix() == 13);
|
|
Require(_Stoul_nid_postfix("18446744073709551615", nullptr, 10) == UINT64_MAX);
|
|
Require(_Stoul_nid_postfix("-1", nullptr, 10) == UINT64_MAX && *__error_nid_postfix() == 13);
|
|
*__error_nid_postfix() = 0;
|
|
}
|
|
|
|
static void CheckFloatClassification() {
|
|
Require(_FInf_nid_postfix.bits[0] == 0x7f800000u && _FNan_nid_postfix.bits[0] == 0x7fc00000u);
|
|
for (int word = 1; word < 4; ++word) Require(_FInf_nid_postfix.bits[word] == 0 && _FNan_nid_postfix.bits[word] == 0);
|
|
const struct { std::uint32_t bits; short code; } cases[] = {
|
|
{0x00000000u, 0}, {0x80000000u, 0}, {0x00000001u, -2}, {0x807fffffu, -2}, {0x00800000u, -1},
|
|
{0xbf800000u, -1}, {0x7f7fffffu, -1}, {0x7f800000u, 1}, {0xff800000u, 1}, {0x7f800001u, 2},
|
|
{0x7fc00000u, 2}, {0xff810000u, 2}, {0x7f810000u, 2},
|
|
};
|
|
for (const auto& test : cases) {
|
|
float value;
|
|
std::memcpy(&value, &test.bits, sizeof(value));
|
|
if (_FDtest_nid_postfix(&value) != test.code) {
|
|
std::fprintf(stderr, "Guest _FDtest failed for %08x\n", test.bits);
|
|
std::abort();
|
|
}
|
|
const int fpclass = test.code == 0 ? 0x10 : test.code == -2 ? 0x08 : test.code == -1 ? 0x04 : test.code == 1 ? 0x01 : 0x02;
|
|
if (__fpclassifyf_nid_postfix(value) != fpclass) {
|
|
std::fprintf(stderr, "Guest __fpclassifyf failed for %08x\n", test.bits);
|
|
std::abort();
|
|
}
|
|
}
|
|
Require(_FDtest_nid_postfix(reinterpret_cast<const float*>(&_FInf_nid_postfix)) == 1);
|
|
Require(_FDtest_nid_postfix(reinterpret_cast<const float*>(&_FNan_nid_postfix)) == 2);
|
|
}
|
|
|
|
int main() {
|
|
CheckFloatClassification();
|
|
CheckIntegerConversions();
|
|
Require(atof_nid_postfix(" -12.5tail") == -12.5);
|
|
char* end = nullptr;
|
|
const char input[] = "0x1.8p+2 remainder";
|
|
Require(strtof_nid_postfix(input, &end) == 6.f && end == input + 8);
|
|
const char invalid[] = "invalid";
|
|
Require(strtof_nid_postfix(invalid, &end) == 0.f && end == invalid);
|
|
*__error_nid_postfix() = 0;
|
|
Require(std::isinf(strtof_nid_postfix("1e1000", nullptr)));
|
|
Require(*__error_nid_postfix() == 34);
|
|
Require(strtold_nid_postfix("1.0000000000000000001!", &end) > 1.L && *end == '!');
|
|
Require(fmodf_nid_postfix(5.5f, 2.f) == 1.5f);
|
|
Require(fmodf_nid_postfix(-5.5f, 2.f) == -1.5f);
|
|
Require(std::signbit(fmodf_nid_postfix(-4.f, 2.f)));
|
|
Require(std::isnan(fmodf_nid_postfix(1.f, 0.f)));
|
|
Require(std::abs(asinf_nid_postfix(0.5f) - 0.5235988f) < 0.000001f);
|
|
Require(std::abs(acosf_nid_postfix(0.5f) - 1.0471976f) < 0.000001f);
|
|
Require(std::abs(atan2f_nid_postfix(1.f, -1.f) - 2.3561945f) < 0.000001f);
|
|
Require(tanf_nid_postfix(0.f) == 0.f);
|
|
Require(hypot_nid_postfix(3.0, 4.0) == 5.0 && hypot_nid_postfix(-3.0, -4.0) == 5.0 && hypotf_nid_postfix(3.f, -4.f) == 5.f);
|
|
Require(std::abs(hypot_nid_postfix(1e308, 1e308) / 1.4142135623730951e308 - 1.0) < 1e-15);
|
|
Require(std::abs(hypotf_nid_postfix(2e38f, 2e38f) / 2.8284271e38f - 1.f) < 1e-6f);
|
|
Require(std::isinf(hypot_nid_postfix(std::numeric_limits<double>::infinity(), std::numeric_limits<double>::quiet_NaN())));
|
|
Require(std::isinf(hypotf_nid_postfix(std::numeric_limits<float>::quiet_NaN(), -std::numeric_limits<float>::infinity())));
|
|
Require(std::isnan(hypot_nid_postfix(1.0, std::numeric_limits<double>::quiet_NaN())));
|
|
for (const bool signalingFirst : {true, false}) {
|
|
const float signaling = std::bit_cast<float>(std::uint32_t{0x7f800001});
|
|
const float infinity = std::numeric_limits<float>::infinity();
|
|
std::feclearexcept(FE_ALL_EXCEPT);
|
|
const float result = signalingFirst ? hypotf_nid_postfix(signaling, infinity) : hypotf_nid_postfix(infinity, signaling);
|
|
Require(std::isinf(result) && result > 0.f && std::fetestexcept(FE_INVALID) != 0);
|
|
}
|
|
Require(log10f_nid_postfix(100.f) == 2.f);
|
|
Require(logbf_nid_postfix(8.f) == 3.f && logbf_nid_postfix(-0.75f) == -1.f);
|
|
Require(logbf_nid_postfix(std::numeric_limits<float>::denorm_min()) == -149.f);
|
|
Require(logbf_nid_postfix(0.f) == -std::numeric_limits<float>::infinity());
|
|
Require(logbf_nid_postfix(-std::numeric_limits<float>::infinity()) == std::numeric_limits<float>::infinity());
|
|
Require(std::isnan(logbf_nid_postfix(std::numeric_limits<float>::quiet_NaN())));
|
|
Require(exp2_nid_postfix(-3.) == 0.125);
|
|
Require(ldexp_nid_postfix(0.75, 4) == 12.);
|
|
Require(scalbn_nid_postfix(0.75, -2) == 0.1875);
|
|
Require(scalbnf_nid_postfix(0.75f, 4) == 12.f);
|
|
int exponent = 0;
|
|
Require(frexp_nid_postfix(12., &exponent) == 0.75 && exponent == 4);
|
|
Require(frexpf_nid_postfix(-12.f, &exponent) == -0.75f && exponent == 4);
|
|
Require(lround_nid_postfix(4294967296.5) == INT64_C(4294967297));
|
|
Require(lround_nid_postfix(-2.5) == -3);
|
|
Require(lroundf_nid_postfix(4294967296.f) == INT64_C(4294967296));
|
|
Require(lroundf_nid_postfix(2.5f) == 3);
|
|
Require(llround_nid_postfix(-4294967296.5) == -INT64_C(4294967297));
|
|
const auto infinity = std::numeric_limits<float>::infinity();
|
|
const auto nan = std::numeric_limits<float>::quiet_NaN();
|
|
Require(__isinff_nid_postfix(infinity) == 1 && __isinff_nid_postfix(-infinity) == 1);
|
|
Require(__isinff_nid_postfix(nan) == 0 && __isinff_nid_postfix(1.f) == 0);
|
|
Require(__isfinitef_nid_postfix(0.f) == 1 && __isfinitef_nid_postfix(infinity) == 0);
|
|
Require(__isfinitef_nid_postfix(nan) == 0);
|
|
Require(__isnormalf_nid_postfix(1.f) == 1 && __isnormalf_nid_postfix(0.f) == 0);
|
|
Require(__isnormalf_nid_postfix(std::numeric_limits<float>::denorm_min()) == 0);
|
|
Require(__isnormal_nid_postfix(1.) == 1 && __isnormal_nid_postfix(0.) == 0);
|
|
Require(__isnormal_nid_postfix(std::numeric_limits<double>::denorm_min()) == 0);
|
|
const auto quotient = div_nid_postfix(7, 2);
|
|
Require(quotient.quot == 3 && quotient.rem == 1);
|
|
const auto negativeNumerator = div_nid_postfix(-7, 2);
|
|
Require(negativeNumerator.quot == -3 && negativeNumerator.rem == -1);
|
|
const auto negativeDenominator = div_nid_postfix(7, -2);
|
|
Require(negativeDenominator.quot == -3 && negativeDenominator.rem == 1);
|
|
const auto minimum = div_nid_postfix(std::numeric_limits<int>::min(), 10);
|
|
Require(minimum.quot == -214748364 && minimum.rem == -8);
|
|
}
|