Add funcs "kernaux_utoa16" and "kernaux_itoa16"

This commit is contained in:
Alex Kotov 2022-01-24 02:40:13 +05:00
parent 81f89a65b1
commit 92ecb5f7eb
Signed by: kotovalexarian
GPG Key ID: 553C0EBBEB5D5F08
9 changed files with 423 additions and 15 deletions

View File

@ -4,6 +4,7 @@
* include/kernaux/libc.h: Add funcs "atoi", "isdigit", "isspace"
* include/kernaux/ntoa.h: Rename const "KERNAUX_ITOA_BUFFER_SIZE" to
"KERNAUX_ITOA10_BUFFER_SIZE"
* include/kernaux/ntoa.h: Add funcs "kernaux_utoa16" and "kernaux_itoa16"
2022-01-22 Alex Kotov <kotovalexarian@gmail.com>

View File

@ -8,12 +8,21 @@ extern "C" {
#include <stdint.h>
// uint64_t: "18446744073709551615"
// int64_t: "9223372036854775807"
// int64_t: "-9223372036854775808"
#define KERNAUX_ITOA10_BUFFER_SIZE 21
// uint64_t: "ffffffffffffffff"
// int64_t: "7fffffffffffffff"
// int64_t: "-8000000000000000"
#define KERNAUX_ITOA16_BUFFER_SIZE 18
void kernaux_utoa10(uint64_t value, char *buffer);
void kernaux_itoa10(int64_t value, char *buffer);
void kernaux_utoa16(uint64_t value, char *buffer);
void kernaux_itoa16(int64_t value, char *buffer);
#ifdef __cplusplus
}
#endif

View File

@ -13,6 +13,8 @@ end
have_func 'kernaux_utoa10'
have_func 'kernaux_itoa10'
have_func 'kernaux_utoa16'
have_func 'kernaux_itoa16'
have_func 'kernaux_snprintf'

View File

@ -7,6 +7,12 @@ static VALUE rb_KernAux_utoa10(VALUE self, VALUE number);
#ifdef HAVE_KERNAUX_ITOA10
static VALUE rb_KernAux_itoa10(VALUE self, VALUE number);
#endif
#ifdef HAVE_KERNAUX_UTOA16
static VALUE rb_KernAux_utoa16(VALUE self, VALUE number);
#endif
#ifdef HAVE_KERNAUX_ITOA16
static VALUE rb_KernAux_itoa16(VALUE self, VALUE number);
#endif
static ID rb_intern_LESS = Qnil;
static ID rb_intern_freeze = Qnil;
@ -24,6 +30,12 @@ void init_ntoa()
#ifdef HAVE_KERNAUX_ITOA10
rb_define_singleton_method(rb_KernAux, "itoa10", rb_KernAux_itoa10, 1);
#endif
#ifdef HAVE_KERNAUX_UTOA16
rb_define_singleton_method(rb_KernAux, "utoa16", rb_KernAux_utoa16, 1);
#endif
#ifdef HAVE_KERNAUX_ITOA16
rb_define_singleton_method(rb_KernAux, "itoa16", rb_KernAux_itoa16, 1);
#endif
}
#ifdef HAVE_KERNAUX_UTOA10
@ -52,3 +64,30 @@ VALUE rb_KernAux_itoa10(
return rb_funcall(rb_str_new2(buffer), rb_intern_freeze, 0);
}
#endif
#ifdef HAVE_KERNAUX_UTOA16
VALUE rb_KernAux_utoa16(
const VALUE self_rb __attribute__((unused)),
const VALUE number_rb
) {
RB_INTEGER_TYPE_P(number_rb);
if (rb_funcall(number_rb, rb_intern_LESS, 1, INT2FIX(0))) {
rb_raise(rb_eRangeError, "can't convert negative number to uint64_t");
}
char buffer[KERNAUX_ITOA16_BUFFER_SIZE];
kernaux_utoa16(NUM2ULL(number_rb), buffer);
return rb_funcall(rb_str_new2(buffer), rb_intern_freeze, 0);
}
#endif
#ifdef HAVE_KERNAUX_ITOA16
VALUE rb_KernAux_itoa16(
const VALUE self_rb __attribute__((unused)),
const VALUE number_rb
) {
RB_INTEGER_TYPE_P(number_rb);
char buffer[KERNAUX_ITOA16_BUFFER_SIZE];
kernaux_itoa16(NUM2LL(number_rb), buffer);
return rb_funcall(rb_str_new2(buffer), rb_intern_freeze, 0);
}
#endif

View File

@ -0,0 +1,63 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe KernAux, '.itoa16' do
if described_class.singleton_class.method_defined? :itoa16
subject(:itoa16) { described_class.itoa16 number }
let(:number) { rand((-2**63)..(2**63 - 1)) }
it { is_expected.to be_instance_of String }
it { is_expected.to be_frozen }
it { is_expected.to eq number.to_s 16 }
context 'when number is 0' do
let(:number) { 0 }
it { is_expected.to eq '0' }
end
context 'when number is 1' do
let(:number) { 1 }
it { is_expected.to eq '1' }
end
context 'when number is -1' do
let(:number) { -1 }
it { is_expected.to eq '-1' }
end
context 'when number is min int64_t' do
let(:number) { -2**63 }
it { is_expected.to eq number.to_s 16 }
end
context 'when number is max int64_t' do
let(:number) { 2**63 - 1 }
it { is_expected.to eq number.to_s 16 }
end
context 'when number is lesser than min uint64_t' do
let(:number) { -2**63 - 1 }
specify do
expect { itoa16 }.to raise_error \
RangeError, 'bignum too big to convert into `long long\''
end
end
context 'when number is greater than max uint64_t' do
let(:number) { 2**63 }
specify do
expect { itoa16 }.to raise_error \
RangeError, 'bignum too big to convert into `long long\''
end
end
end
end

View File

@ -0,0 +1,45 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe KernAux, '.utoa16' do
if described_class.singleton_class.method_defined? :utoa16
subject(:utoa16) { described_class.utoa16 number }
let(:number) { rand 0..(2**64 - 1) }
it { is_expected.to be_instance_of String }
it { is_expected.to be_frozen }
it { is_expected.to eq number.to_s 16 }
context 'when number is 0' do
let(:number) { 0 }
it { is_expected.to eq '0' }
end
context 'when number is max uint64_t' do
let(:number) { 2**64 - 1 }
it { is_expected.to eq number.to_s 16 }
end
context 'when number is -1' do
let(:number) { -1 }
specify do
expect { utoa16 }.to \
raise_error RangeError, 'can\'t convert negative number to uint64_t'
end
end
context 'when number is greater than max uint64_t' do
let(:number) { 2**64 }
specify do
expect { utoa16 }.to raise_error \
RangeError, 'bignum too big to convert into `unsigned long long\''
end
end
end
end

View File

@ -7,6 +7,10 @@ extern "C" {
fn kernaux_utoa10(value: u64, buffer: *mut c_char);
#[cfg(test)]
fn kernaux_itoa10(value: i64, buffer: *mut c_char);
#[cfg(test)]
fn kernaux_utoa16(value: u64, buffer: *mut c_char);
#[cfg(test)]
fn kernaux_itoa16(value: i64, buffer: *mut c_char);
}
#[cfg(test)]
@ -38,4 +42,28 @@ mod tests {
unsafe { CStr::from_ptr(buffer.as_ptr()) }.to_str().unwrap();
assert_eq!(result, "-123");
}
#[test]
fn utoa16() {
let mut buffer: [i8; 1000] = [0; 1000];
unsafe { kernaux_utoa16(0x123, buffer.as_mut_ptr()) };
let result =
unsafe { CStr::from_ptr(buffer.as_ptr()) }.to_str().unwrap();
assert_eq!(result, "123");
}
#[test]
fn itoa16() {
let mut buffer: [i8; 1000] = [0; 1000];
unsafe { kernaux_itoa16(0x123, buffer.as_mut_ptr()) };
let result =
unsafe { CStr::from_ptr(buffer.as_ptr()) }.to_str().unwrap();
assert_eq!(result, "123");
let mut buffer: [i8; 1000] = [0; 1000];
unsafe { kernaux_itoa16(-0x123, buffer.as_mut_ptr()) };
let result =
unsafe { CStr::from_ptr(buffer.as_ptr()) }.to_str().unwrap();
assert_eq!(result, "-123");
}
}

View File

@ -33,3 +33,34 @@ void kernaux_itoa10(int64_t value, char *buffer)
kernaux_utoa10(-value, buffer);
}
}
void kernaux_utoa16(uint64_t value, char *buffer)
{
char *pos = buffer;
if (value == 0) *(pos++) = '0';
while (value > 0) {
char mod = value % 16;
*(pos++) = mod < 10 ? mod + '0' : mod - 10 + 'a';
value = value / 16;
}
*(pos--) = '\0';
while (buffer < pos) {
const char tmp = *buffer;
*(buffer++) = *pos;
*(pos--) = tmp;
}
}
void kernaux_itoa16(int64_t value, char *buffer)
{
if (value >= 0) {
kernaux_utoa16(value, buffer);
} else {
*(buffer++) = '-';
kernaux_utoa16(-value, buffer);
}
}

View File

@ -5,6 +5,7 @@
#include <kernaux/ntoa.h>
#include <assert.h>
#include <stddef.h>
#include <string.h>
static const struct {
@ -94,26 +95,215 @@ static const struct {
{ INT64_MIN, "-9223372036854775808" },
};
static const struct {
uint64_t value;
const char *result;
} utoa16_cases[] = {
{ 0x0, "0" }, { 0x1, "1" },
{ 0x2, "2" }, { 0x9, "9" },
{ 0xa, "a" }, { 0xb, "b" },
{ 0xc, "c" }, { 0xd, "d" },
{ 0xe, "e" }, { 0xf, "f" },
{ 0x10, "10" }, { 0x11, "11" },
{ 0x12, "12" }, { 0x19, "19" },
{ 0x1a, "1a" }, { 0x1b, "1b" },
{ 0x1c, "1c" }, { 0x1d, "1d" },
{ 0x1e, "1e" }, { 0x1f, "1f" },
{ 0x20, "20" }, { 0x21, "21" },
{ 0x22, "22" }, { 0x29, "29" },
{ 0x2a, "2a" }, { 0x2b, "2b" },
{ 0x2c, "2c" }, { 0x2d, "2d" },
{ 0x2e, "2e" }, { 0x2f, "2f" },
{ 0x90, "90" }, { 0x91, "91" },
{ 0x92, "92" }, { 0x99, "99" },
{ 0x9a, "9a" }, { 0x9b, "9b" },
{ 0x9c, "9c" }, { 0x9d, "9d" },
{ 0x9e, "9e" }, { 0x9f, "9f" },
{ 0xa0, "a0" }, { 0xa1, "a1" },
{ 0xa2, "a2" }, { 0xa9, "a9" },
{ 0xaa, "aa" }, { 0xab, "ab" },
{ 0xac, "ac" }, { 0xad, "ad" },
{ 0xae, "ae" }, { 0xaf, "af" },
{ 0xb0, "b0" }, { 0xb1, "b1" },
{ 0xb2, "b2" }, { 0xb9, "b9" },
{ 0xba, "ba" }, { 0xbb, "bb" },
{ 0xbc, "bc" }, { 0xbd, "bd" },
{ 0xbe, "be" }, { 0xbf, "bf" },
{ 0xc0, "c0" }, { 0xc1, "c1" },
{ 0xc2, "c2" }, { 0xc9, "c9" },
{ 0xca, "ca" }, { 0xcb, "cb" },
{ 0xcc, "cc" }, { 0xcd, "cd" },
{ 0xce, "ce" }, { 0xcf, "cf" },
{ 0xd0, "d0" }, { 0xd1, "d1" },
{ 0xd2, "d2" }, { 0xd9, "d9" },
{ 0xda, "da" }, { 0xdb, "db" },
{ 0xdc, "dc" }, { 0xdd, "dd" },
{ 0xde, "de" }, { 0xdf, "df" },
{ 0xe0, "e0" }, { 0xe1, "e1" },
{ 0xe2, "e2" }, { 0xe9, "e9" },
{ 0xea, "ea" }, { 0xeb, "eb" },
{ 0xec, "ec" }, { 0xed, "ed" },
{ 0xee, "ee" }, { 0xef, "ef" },
{ 0xf0, "f0" }, { 0xf1, "f1" },
{ 0xf2, "f2" }, { 0xf9, "f9" },
{ 0xfa, "fa" }, { 0xfb, "fb" },
{ 0xfc, "fc" }, { 0xfd, "fd" },
{ 0xfe, "fe" }, { 0xff, "ff" },
{ 0x100, "100" }, { 0x101, "101" },
{ 0x109, "109" }, { 0x10a, "10a" },
{ 0x10f, "10f" },
{ 0x110, "110" }, { 0x111, "111" },
{ 0x119, "119" }, { 0x11a, "11a" },
{ 0x11f, "11f" }, { 0x120, "120" },
{ 0x1ff, "1ff" }, { 0x200, "200" },
{ 0xfff, "fff" }, { 0x1000, "1000" },
{ UINT16_MAX, "ffff" },
{ UINT16_MAX + 1, "10000" },
{ UINT32_MAX, "ffffffff" },
{ (uint64_t)UINT32_MAX + 1, "100000000" },
{ UINT64_MAX - 6, "fffffffffffffff9" },
{ UINT64_MAX - 5, "fffffffffffffffa" },
{ UINT64_MAX - 1, "fffffffffffffffe" },
{ UINT64_MAX, "ffffffffffffffff" },
};
static const struct {
int64_t value;
const char *result;
} itoa16_cases[] = {
{ 0x0, "0" }, { 0x1, "1" },
{ 0x2, "2" }, { 0x9, "9" },
{ 0xa, "a" }, { 0xb, "b" },
{ 0xc, "c" }, { 0xd, "d" },
{ 0xe, "e" }, { 0xf, "f" },
{ 0x10, "10" }, { 0x11, "11" },
{ 0x12, "12" }, { 0x19, "19" },
{ 0x1a, "1a" }, { 0x1b, "1b" },
{ 0x1c, "1c" }, { 0x1d, "1d" },
{ 0x1e, "1e" }, { 0x1f, "1f" },
{ 0x20, "20" }, { 0x21, "21" },
{ 0x22, "22" }, { 0x29, "29" },
{ 0x2a, "2a" }, { 0x2b, "2b" },
{ 0x2c, "2c" }, { 0x2d, "2d" },
{ 0x2e, "2e" }, { 0x2f, "2f" },
{ 0x90, "90" }, { 0x91, "91" },
{ 0x92, "92" }, { 0x99, "99" },
{ 0x9a, "9a" }, { 0x9b, "9b" },
{ 0x9c, "9c" }, { 0x9d, "9d" },
{ 0x9e, "9e" }, { 0x9f, "9f" },
{ 0xa0, "a0" }, { 0xa1, "a1" },
{ 0xa2, "a2" }, { 0xa9, "a9" },
{ 0xaa, "aa" }, { 0xab, "ab" },
{ 0xac, "ac" }, { 0xad, "ad" },
{ 0xae, "ae" }, { 0xaf, "af" },
{ 0xb0, "b0" }, { 0xb1, "b1" },
{ 0xb2, "b2" }, { 0xb9, "b9" },
{ 0xba, "ba" }, { 0xbb, "bb" },
{ 0xbc, "bc" }, { 0xbd, "bd" },
{ 0xbe, "be" }, { 0xbf, "bf" },
{ 0xc0, "c0" }, { 0xc1, "c1" },
{ 0xc2, "c2" }, { 0xc9, "c9" },
{ 0xca, "ca" }, { 0xcb, "cb" },
{ 0xcc, "cc" }, { 0xcd, "cd" },
{ 0xce, "ce" }, { 0xcf, "cf" },
{ 0xd0, "d0" }, { 0xd1, "d1" },
{ 0xd2, "d2" }, { 0xd9, "d9" },
{ 0xda, "da" }, { 0xdb, "db" },
{ 0xdc, "dc" }, { 0xdd, "dd" },
{ 0xde, "de" }, { 0xdf, "df" },
{ 0xe0, "e0" }, { 0xe1, "e1" },
{ 0xe2, "e2" }, { 0xe9, "e9" },
{ 0xea, "ea" }, { 0xeb, "eb" },
{ 0xec, "ec" }, { 0xed, "ed" },
{ 0xee, "ee" }, { 0xef, "ef" },
{ 0xf0, "f0" }, { 0xf1, "f1" },
{ 0xf2, "f2" }, { 0xf9, "f9" },
{ 0xfa, "fa" }, { 0xfb, "fb" },
{ 0xfc, "fc" }, { 0xfd, "fd" },
{ 0xfe, "fe" }, { 0xff, "ff" },
{ 0x100, "100" }, { 0x101, "101" },
{ 0x109, "109" }, { 0x10a, "10a" },
{ 0x10f, "10f" },
{ 0x110, "110" }, { 0x111, "111" },
{ 0x119, "119" }, { 0x11a, "11a" },
{ 0x11f, "11f" }, { 0x120, "120" },
{ 0x1ff, "1ff" }, { 0x200, "200" },
{ 0xfff, "fff" }, { 0x1000, "1000" },
{ UINT16_MAX, "ffff" },
{ UINT16_MAX + 1, "10000" },
{ UINT32_MAX, "ffffffff" },
{ (uint64_t)UINT32_MAX + 1, "100000000" },
{ INT64_MIN + 7, "-7ffffffffffffff9" },
{ INT64_MAX - 6, "7ffffffffffffff9" },
{ INT64_MIN + 6, "-7ffffffffffffffa" },
{ INT64_MAX - 5, "7ffffffffffffffa" },
{ INT64_MIN + 2, "-7ffffffffffffffe" },
{ INT64_MAX - 1, "7ffffffffffffffe" },
{ INT64_MIN + 1, "-7fffffffffffffff" },
{ INT64_MAX, "7fffffffffffffff" },
{ INT64_MIN, "-8000000000000000" },
};
int main()
{
char buffer[KERNAUX_ITOA10_BUFFER_SIZE];
{
char buffer[KERNAUX_ITOA10_BUFFER_SIZE];
for (
size_t index = 0;
index < sizeof(utoa10_cases) / sizeof(utoa10_cases[0]);
++index
) {
kernaux_utoa10(utoa10_cases[index].value, buffer);
assert(strcmp(buffer, utoa10_cases[index].result) == 0);
for (
size_t index = 0;
index < sizeof(utoa10_cases) / sizeof(utoa10_cases[0]);
++index
) {
kernaux_utoa10(utoa10_cases[index].value, buffer);
assert(strcmp(buffer, utoa10_cases[index].result) == 0);
}
for (
size_t index = 0;
index < sizeof(itoa10_cases) / sizeof(itoa10_cases[0]);
++index
) {
const int64_t value = itoa10_cases[index].value;
kernaux_itoa10(value, buffer);
assert(strcmp(buffer, itoa10_cases[index].result) == 0);
if (value <= 0) continue;
kernaux_itoa10(-value, buffer);
assert(buffer[0] == '-');
assert(strcmp(&buffer[1], itoa10_cases[index].result) == 0);
}
}
for (
size_t index = 0;
index < sizeof(itoa10_cases) / sizeof(itoa10_cases[0]);
++index
) {
kernaux_itoa10(itoa10_cases[index].value, buffer);
assert(strcmp(buffer, itoa10_cases[index].result) == 0);
{
char buffer[KERNAUX_ITOA16_BUFFER_SIZE];
for (
size_t index = 0;
index < sizeof(utoa16_cases) / sizeof(utoa16_cases[0]);
++index
) {
kernaux_utoa16(utoa16_cases[index].value, buffer);
assert(strcmp(buffer, utoa16_cases[index].result) == 0);
}
for (
size_t index = 0;
index < sizeof(itoa16_cases) / sizeof(itoa16_cases[0]);
++index
) {
const int64_t value = itoa16_cases[index].value;
kernaux_itoa16(value, buffer);
assert(strcmp(buffer, itoa16_cases[index].result) == 0);
if (value <= 0) continue;
kernaux_itoa16(-value, buffer);
assert(buffer[0] == '-');
assert(strcmp(&buffer[1], itoa16_cases[index].result) == 0);
}
}
return 0;