Skip to content

Commit

Permalink
[feat, fix, test] ulbi_print_ex now can write lowercase letters; (u…
Browse files Browse the repository at this point in the history
…lbn.hpp) allow more formats of `std::ostream` for `print`; add template specialization for `std::formatter`; fix bad `print`; add tests
  • Loading branch information
DreamPast committed Dec 21, 2024
1 parent 158450f commit 3520f32
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 92 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ Depends on the following C++20 features:
- Concepts and constranints
- Three-way comparison
- `<bit>` header file
- std::span
- std::format

### test

Expand Down
2 changes: 2 additions & 0 deletions README_zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
- 约束与概念
- 三路比较
- \<bit\>头文件
- std::span
- std::format

### test

Expand Down
44 changes: 36 additions & 8 deletions test/cxx20/test_cast_to.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#include "test.hpp"
#include <format>
#include <iomanip>
#include <sstream>

void testBigString() {
puts("======Test Big String");
Expand All @@ -24,28 +27,53 @@ void testBigString() {
}
}
void test() {
puts("---Some integers");
T_assert_eq(BigInt("0").toString(), "0");
T_assert_eq(BigInt("12").toString(), "12");
T_assert_eq(BigInt("-12").toString(), "-12");
T_assert_eq(BigInt("12345678901234567890").toString(), "12345678901234567890");
T_assert_eq(BigInt("012").toString(8), "12");
T_assert_eq(BigInt("0x12").toString(16), "12");

T_assert_eq(std::format("{}", BigInt("0")), "0");
T_assert_eq(std::format("{}", BigInt("12")), "12");
T_assert_eq(std::format("{}", BigInt("-12")), "-12");
T_assert_eq(std::format("{}", BigInt("12345678901234567890")), "12345678901234567890");

T_assert_exception([] { (12_bi).toString(0); }, ULBN_ERR_EXCEED_RANGE);

for(int i = -LIMIT; i <= LIMIT; ++i)
for(int i = -LIMIT; i <= LIMIT; ++i) {
T_assert_eq(BigInt(i).toString(), std::to_string(i));
T_assert_eq(std::format("{}", BigInt(i)), std::to_string(i));
}


puts("---Print");
BigInt("12345678901234567890").print(std::cout);
fprintf(stdout, "\n");
BigInt("-12345678901234567890").print(std::cout);
fprintf(stdout, "\n");
T_assert_exception([] { BigInt("12345678901234567890").print(stdout, 0); }, ULBN_ERR_EXCEED_RANGE);

puts("---Float, Double, Long double");

for(auto base: { 8, 10, 16 })
for(auto uppercase: { false, true })
for(auto showbase: { false, true }) {
BigInt obj("12345678901234567890");
std::ostringstream osst;

if(base == 8)
osst << std::oct;
else if(base == 10)
osst << std::dec;
else if(base == 16)
osst << std::hex;
osst << (uppercase ? std::uppercase : std::nouppercase);
osst << (showbase ? std::showbase : std::noshowbase);
osst << obj;

T_assert_eq(obj, BigInt::fromString(osst.str(), showbase ? 0 : base));
}


T_assert_eq(BigInt(0.0).toDouble(), 0.0);
T_assert_eq(BigInt(-0.0).toDouble(), 0.0);
T_assert_eq(BigInt(1.0).toDouble(), 1.0);
Expand All @@ -63,7 +91,7 @@ void test() {
T_assert_eq(BigInt(1.0).toLongDouble(), 1.0L);
T_assert_eq(BigInt(-1.0).toLongDouble(), -1.0L);

puts("---Fit/To slong/ulong/limb/slimb");

for(ulbn_slong_t i = -LIMIT; i <= LIMIT; ++i) {
T_assert_eq(BigInt(i).toSlong(), i);
T_assert_eq(BigInt(i).toUlong(), static_cast<ulbn_ulong_t>(i));
Expand All @@ -76,7 +104,7 @@ void test() {
T_assert_eq(BigInt(i).fitSlimb(), fitType<ulbn_slimb_t>(i));
}

puts("---Fit/To float/double/longdouble");

for(ulbn_slong_t i = -LIMIT; i <= LIMIT; ++i) {
float fd = BigInt(i).toFloat();
T_assert_eq(fd, static_cast<float>(i));
Expand All @@ -103,14 +131,14 @@ void test() {
T_assert_eq(BigInt(static_cast<long double>(i) - 0.5L).toLongDouble(), static_cast<long double>(i));
}

puts("---Random");

for(int t = TEST_SMALL; t--;) {
BigInt x = BigInt::fromRandom(1024).asInt(1024);
auto str = x.toString();
T_assert_eq(str, BigInt(str));
}

puts("---Random (10pow)");

for(int t = TEST_SMALL; t--;) {
BigInt x = BigInt(10).pow(BigInt::fromRandom(12));
auto str = x.toString();
Expand Down
25 changes: 14 additions & 11 deletions ulbn.c
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,7 @@ ULBN_INTERNAL ulbn_usize_t ulbn_set_ulong(ulbn_limb_t* p, ulbn_ulong_t v) {
}


static const char _ULBN_LOWER_TABLE[] = "0123456789abcdefghijklmnopqrstuvwxyz";
static const char _ULBN_UPPER_TABLE[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
#if 0
ul_unused ULBN_INTERNAL void ulbn_dumplimb(FILE* fp, ulbn_limb_t l) {
Expand Down Expand Up @@ -2976,7 +2977,6 @@ ULBN_INTERNAL void ulbn_prepare_baseconv(ulbn_baseconv_t* conv, ulbn_limb_t base
++conv->base_pow;
conv->bi = ulbn_divinv1(conv->b);
#endif
conv->char_table = _ULBN_UPPER_TABLE;
}
ULBN_INTERNAL int ulbn_conv2print_generic(
const ulbn_alloc_t* alloc, size_t desire_len, /* */
Expand Down Expand Up @@ -7522,9 +7522,8 @@ ULBN_PUBLIC void ulbi_to_bytes_signed_be(const ulbi_t* ao, void* dst, size_t siz
****************************/

ULBN_PRIVATE int _ulbi_print_ex(
const ulbn_alloc_t* alloc, /* */
ulbn_printer_t* printer, void* opaque, /* */
ulbi_t* ao, int base, size_t desire_len /* */
const ulbn_alloc_t* alloc, ulbn_printer_t* printer, void* opaque, /* */
ulbi_t* ao, int base, size_t desire_len, const char* char_table /* */
) {
/**
* Fast base conversion algorithm:
Expand Down Expand Up @@ -7559,8 +7558,9 @@ ULBN_PRIVATE int _ulbi_print_ex(
ULBN_DO_IF_PUBLIC_COND(err < 0, goto cleanup;);
ulbi_deinit(alloc, _do);

err =
_ulbi_print_ex(alloc, printer, opaque, qo, base, desire_len > pow ? ul_static_cast(size_t, desire_len - pow) : 0);
err = _ulbi_print_ex(
alloc, printer, opaque, qo, base, desire_len > pow ? ul_static_cast(size_t, desire_len - pow) : 0, char_table
);
ULBN_DO_IF_PUBLIC_COND(err < 0, goto cleanup;);
desire_len = ul_static_cast(size_t, pow);
}
Expand All @@ -7569,6 +7569,7 @@ ULBN_PRIVATE int _ulbi_print_ex(
if(ao->len != 0) {
ulbn_baseconv_t conv;
ulbn_prepare_baseconv(&conv, _ulbn_cast_limb(base));
conv.char_table = char_table;
err = ulbn_conv2print_generic(alloc, desire_len, printer, opaque, _ulbi_limbs(ao), ulbn_cast_usize(ao->len), &conv);
} else
err = _ulbn_write0(printer, opaque, desire_len);
Expand All @@ -7580,14 +7581,13 @@ ULBN_PRIVATE int _ulbi_print_ex(
}

ULBN_PUBLIC int ulbi_print_ex(
const ulbn_alloc_t* alloc, /* */
ulbn_printer_t* printer, void* opaque, /* */
const ulbi_t* ao, int base /* */
const ulbn_alloc_t* alloc, ulbn_printer_t* printer, void* opaque, /* */
const ulbi_t* ao, int base /* */
) {
ulbi_t ro[1] = { ULBI_INIT };
int err;

if(ul_unlikely(base < 2 || base > 36))
if(ul_unlikely(!((base >= 2 && base <= 36) || (base >= -36 && base <= -2))))
return ULBN_ERR_EXCEED_RANGE;
if(ao->len == 0)
return ul_unlikely(printer(opaque, "0", 1)) ? ULBN_ERR_EXTERNAL : 0;
Expand All @@ -7596,7 +7596,10 @@ ULBN_PUBLIC int ulbi_print_ex(

err = ulbi_abs(alloc, ro, ao);
ULBN_RETURN_IF_ALLOC_COND(err < 0, err);
err = _ulbi_print_ex(alloc, printer, opaque, ro, base, 0);
if(base > 0)
err = _ulbi_print_ex(alloc, printer, opaque, ro, base, 0, _ULBN_UPPER_TABLE);
else
err = _ulbi_print_ex(alloc, printer, opaque, ro, -base, 0, _ULBN_LOWER_TABLE);
ulbi_deinit(alloc, ro);
return err;
}
Expand Down
11 changes: 5 additions & 6 deletions ulbn.h
Original file line number Diff line number Diff line change
Expand Up @@ -1870,7 +1870,7 @@ ULBN_PUBLIC void ulbi_to_bytes_signed_be(const ulbi_t* ao, void* dst, size_t siz
* If `NULL` is passed, `alloc` will be used;
* and then you need to call `ulbn_dealloc` to free the memory.
* @param alloc_opaque Parameter for the allocation function.
* @param base String base (2 <= base <= 36).
* @param base String base (2 <= base <= 36 with uppercase letters, -36 <= base <= -2 with lowercase letters).
*
* @return String if successful (allocated by alloc_func);
* @return `NULL` if out of memory (considered as `ULBN_ERR_NOMEM`);
Expand All @@ -1886,22 +1886,21 @@ ULBN_PUBLIC char* ulbi_to_string_alloc(
* @note The `printer` function should return 0 if successful; otherwise, it should return a non-zero value.
* @warning It's unsafe to throw an exception or do a no-return operation in the `printer` function.
*
* @param base String base (2 <= base <= 36)
* @param base String base (2 <= base <= 36 with uppercase letters, -36 <= base <= -2 with lowercase letters).
*
* @return `ULBN_ERR_NOMEM` if out of memory;
* @return `ULBN_ERR_EXCEED_RANGE` if `base` is invalid;
* @return `ULBN_ERR_EXTERNAL` if `printer` returns non-zero;
* @return `0` if successful.
*/
ULBN_PUBLIC int ulbi_print_ex(
const ulbn_alloc_t* alloc, /* */
ulbn_printer_t* printer, void* opaque, /* */
const ulbi_t* ao, int base /* */
const ulbn_alloc_t* alloc, ulbn_printer_t* printer, void* opaque, /* */
const ulbi_t* ao, int base /* */
);
/**
* @brief Prints `o` to `fp`.
*
* @param base String base (2 <= base <= 36).
* @param base String base (2 <= base <= 36 with uppercase letters, -36 <= base <= -2 with lowercase letters).
*
* @return `ULBN_ERR_NOMEM` if out of memory;
* @return `ULBN_ERR_EXCEED_RANGE` if `base` is invalid;
Expand Down
Loading

0 comments on commit 3520f32

Please sign in to comment.