mirror of https://github.com/tailix/libkernaux.git
Common: include/ntoa.h: Functions "kernaux_utoa" and "kernaux_itoa" receive prefix
This commit is contained in:
parent
fdedd2574d
commit
2129255b5a
|
@ -1,3 +1,7 @@
|
|||
2022-05-30 Alex Kotov <kotovalexarian@gmail.com>
|
||||
|
||||
* include/ntoa.h: Functions "kernaux_utoa" and "kernaux_itoa" receive prefix
|
||||
|
||||
2022-05-28 Alex Kotov <kotovalexarian@gmail.com>
|
||||
|
||||
libkernaux 0.3.0 released
|
||||
|
|
|
@ -66,7 +66,7 @@ zero). Work-in-progress APIs can change at any time.
|
|||
* [To human](/examples/units_human.c)
|
||||
* Usual functions
|
||||
* [libc replacement](/include/kernaux/libc.h) (*stable since* **0.1.0**)
|
||||
* [itoa/ftoa replacement](/include/kernaux/ntoa.h) (*stable since* **0.1.0**, *non-breaking since* **0.3.0**)
|
||||
* [itoa/ftoa replacement](/include/kernaux/ntoa.h) (*stable since* **0.1.0**, *non-breaking since* **?.?.?**)
|
||||
* [printf replacement](/include/kernaux/printf.h) (*stable since* **0.1.0**)
|
||||
* Code from [https://github.com/mpaland/printf](https://github.com/mpaland/printf). Thank you!
|
||||
* [printf](/examples/printf.c)
|
||||
|
|
|
@ -28,8 +28,8 @@ extern "C" {
|
|||
// "-8000000000000000"
|
||||
#define KERNAUX_ITOA16_BUFFER_SIZE 18
|
||||
|
||||
char *kernaux_utoa(uint64_t value, char *buffer, int base);
|
||||
char *kernaux_itoa(int64_t value, char *buffer, int base);
|
||||
char *kernaux_utoa(uint64_t value, char *buffer, int base, const char *prefix);
|
||||
char *kernaux_itoa(int64_t value, char *buffer, int base, const char *prefix);
|
||||
|
||||
void kernaux_utoa10(uint64_t value, char *buffer);
|
||||
void kernaux_itoa10(int64_t value, char *buffer);
|
||||
|
|
|
@ -9,8 +9,11 @@
|
|||
#include <mruby/presym.h>
|
||||
#include <mruby/string.h>
|
||||
|
||||
#define MAX_PREFIX_LEN 100
|
||||
|
||||
static mrb_value rb_KernAux_utoa(mrb_state *mrb, mrb_value self);
|
||||
static mrb_value rb_KernAux_itoa(mrb_state *mrb, mrb_value self);
|
||||
|
||||
static mrb_value rb_KernAux_utoa10(mrb_state *mrb, mrb_value self);
|
||||
static mrb_value rb_KernAux_itoa10(mrb_state *mrb, mrb_value self);
|
||||
static mrb_value rb_KernAux_utoa16(mrb_state *mrb, mrb_value self);
|
||||
|
@ -28,9 +31,10 @@ void init_ntoa(mrb_state *const mrb)
|
|||
rb_KernAux_Error);
|
||||
|
||||
mrb_define_class_method(mrb, rb_KernAux, "utoa",
|
||||
rb_KernAux_utoa, MRB_ARGS_REQ(2));
|
||||
rb_KernAux_utoa, MRB_ARGS_REQ(2) | MRB_ARGS_OPT(1));
|
||||
mrb_define_class_method(mrb, rb_KernAux, "itoa",
|
||||
rb_KernAux_itoa, MRB_ARGS_REQ(2));
|
||||
rb_KernAux_itoa, MRB_ARGS_REQ(2) | MRB_ARGS_OPT(1));
|
||||
|
||||
mrb_define_class_method(mrb, rb_KernAux, "utoa10",
|
||||
rb_KernAux_utoa10, MRB_ARGS_REQ(1));
|
||||
mrb_define_class_method(mrb, rb_KernAux, "itoa10",
|
||||
|
@ -45,16 +49,22 @@ mrb_value rb_KernAux_utoa(mrb_state *mrb, mrb_value self)
|
|||
{
|
||||
mrb_int value = 0;
|
||||
mrb_value base;
|
||||
mrb_get_args(mrb, "io", &value, &base);
|
||||
const char *prefix = NULL;
|
||||
mrb_int prefix_len = 0;
|
||||
mrb_get_args(mrb, "io|s!", &value, &base, &prefix, &prefix_len);
|
||||
|
||||
if (value < 0) {
|
||||
mrb_raise(mrb, E_RANGE_ERROR,
|
||||
"can't convert negative number to uint64_t");
|
||||
}
|
||||
if (prefix_len > MAX_PREFIX_LEN || prefix_len < 0) {
|
||||
mrb_raisef(mrb, E_ARGUMENT_ERROR,
|
||||
"prefix length %d is too long", prefix_len);
|
||||
}
|
||||
|
||||
char buffer[KERNAUX_UTOA_BUFFER_SIZE];
|
||||
char buffer[KERNAUX_UTOA_BUFFER_SIZE + prefix_len];
|
||||
current_mrb_start(mrb);
|
||||
kernaux_utoa(value, buffer, convert_base(mrb, base));
|
||||
kernaux_utoa(value, buffer, convert_base(mrb, base), prefix);
|
||||
current_mrb_finish(mrb);
|
||||
|
||||
mrb_value result = mrb_str_new_lit(mrb, "");
|
||||
|
@ -66,11 +76,18 @@ mrb_value rb_KernAux_itoa(mrb_state *mrb, mrb_value self)
|
|||
{
|
||||
mrb_int value = 0;
|
||||
mrb_value base;
|
||||
mrb_get_args(mrb, "io", &value, &base);
|
||||
const char *prefix = NULL;
|
||||
mrb_int prefix_len = 0;
|
||||
mrb_get_args(mrb, "io|s!", &value, &base, &prefix, &prefix_len);
|
||||
|
||||
char buffer[KERNAUX_ITOA_BUFFER_SIZE];
|
||||
if (prefix_len > MAX_PREFIX_LEN || prefix_len < 0) {
|
||||
mrb_raisef(mrb, E_ARGUMENT_ERROR,
|
||||
"prefix length %d is too long", prefix_len);
|
||||
}
|
||||
|
||||
char buffer[KERNAUX_ITOA_BUFFER_SIZE + prefix_len];
|
||||
current_mrb_start(mrb);
|
||||
kernaux_itoa(value, buffer, convert_base(mrb, base));
|
||||
kernaux_itoa(value, buffer, convert_base(mrb, base), prefix);
|
||||
current_mrb_finish(mrb);
|
||||
|
||||
mrb_value result = mrb_str_new_lit(mrb, "");
|
||||
|
|
|
@ -4,6 +4,18 @@ def test_utoa(number, base, expected)
|
|||
assert_true result.instance_of? String
|
||||
assert_true result.frozen?
|
||||
assert_equal expected, result
|
||||
|
||||
result = KernAux.utoa(number, base, nil)
|
||||
|
||||
assert_true result.instance_of? String
|
||||
assert_true result.frozen?
|
||||
assert_equal expected, result
|
||||
|
||||
result = KernAux.utoa(number, base, '')
|
||||
|
||||
assert_true result.instance_of? String
|
||||
assert_true result.frozen?
|
||||
assert_equal expected, result
|
||||
end
|
||||
|
||||
def test_itoa(number, base, expected)
|
||||
|
@ -12,6 +24,34 @@ def test_itoa(number, base, expected)
|
|||
assert_true result.instance_of? String
|
||||
assert_true result.frozen?
|
||||
assert_equal expected, result
|
||||
|
||||
result = KernAux.itoa(number, base, nil)
|
||||
|
||||
assert_true result.instance_of? String
|
||||
assert_true result.frozen?
|
||||
assert_equal expected, result
|
||||
|
||||
result = KernAux.itoa(number, base, '')
|
||||
|
||||
assert_true result.instance_of? String
|
||||
assert_true result.frozen?
|
||||
assert_equal expected, result
|
||||
end
|
||||
|
||||
def test_utoax(number, base, prefix, expected)
|
||||
result = KernAux.utoa(number, base, prefix)
|
||||
|
||||
assert_true result.instance_of? String
|
||||
assert_true result.frozen?
|
||||
assert_equal expected, result
|
||||
end
|
||||
|
||||
def test_itoax(number, base, prefix, expected)
|
||||
result = KernAux.itoa(number, base, prefix)
|
||||
|
||||
assert_true result.instance_of? String
|
||||
assert_true result.frozen?
|
||||
assert_equal expected, result
|
||||
end
|
||||
|
||||
def test_utoa10(number, expected)
|
||||
|
@ -96,6 +136,23 @@ assert 'KernAux.utoa' do
|
|||
|
||||
number = Random.rand(2**32 - 1)
|
||||
test_utoa number, :X, number.to_s(16).upcase
|
||||
|
||||
number = Random.rand(2**32 - 1)
|
||||
base = 2 + Random.rand(36 - 2)
|
||||
prefix = 'foo'
|
||||
test_utoax number, base, prefix, "#{prefix}#{number.abs.to_s(base)}"
|
||||
|
||||
number = Random.rand(2**32 - 1)
|
||||
base = 2 + Random.rand(36 - 2)
|
||||
prefix = 'a' * 100
|
||||
test_utoax number, base, prefix, "#{prefix}#{number.abs.to_s(base)}"
|
||||
|
||||
assert_raise ArgumentError, 'prefix length 101 is too long' do
|
||||
number = Random.rand(2**32 - 1)
|
||||
base = 2 + Random.rand(36 - 2)
|
||||
prefix = 'a' * 101
|
||||
KernAux.utoa(number, base, prefix)
|
||||
end
|
||||
end
|
||||
|
||||
assert 'KernAux.itoa' do
|
||||
|
@ -157,6 +214,25 @@ assert 'KernAux.itoa' do
|
|||
|
||||
number = Random.rand(2**31 - 1) * [1, -1].sample
|
||||
test_itoa number, :X, number.to_s(16).upcase
|
||||
|
||||
number = Random.rand(2**31 - 1) * [1, -1].sample
|
||||
base = 2 + Random.rand(36 - 2)
|
||||
prefix = 'foo'
|
||||
sign = number < 0 ? '-' : ''
|
||||
test_itoax number, base, prefix, "#{sign}#{prefix}#{number.abs.to_s(base)}"
|
||||
|
||||
number = Random.rand(2**31 - 1) * [1, -1].sample
|
||||
base = 2 + Random.rand(36 - 2)
|
||||
prefix = 'a' * 100
|
||||
sign = number < 0 ? '-' : ''
|
||||
test_itoax number, base, prefix, "#{sign}#{prefix}#{number.abs.to_s(base)}"
|
||||
|
||||
assert_raise ArgumentError, 'prefix length 101 is too long' do
|
||||
number = Random.rand(2**31 - 1) * [1, -1].sample
|
||||
base = 2 + Random.rand(36 - 2)
|
||||
prefix = 'a' * 101
|
||||
KernAux.itoa(number, base, prefix)
|
||||
end
|
||||
end
|
||||
|
||||
assert 'KernAux.utoa10' do
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
#include <kernaux.h>
|
||||
#include <ruby.h>
|
||||
|
||||
#define MAX_PREFIX_LEN 100
|
||||
|
||||
#ifdef HAVE_KERNAUX_UTOA
|
||||
static VALUE rb_KernAux_utoa(VALUE self, VALUE number, VALUE base);
|
||||
static VALUE rb_KernAux_utoa(VALUE self, VALUE number, VALUE base, VALUE prefix);
|
||||
#endif
|
||||
#ifdef HAVE_KERNAUX_ITOA
|
||||
static VALUE rb_KernAux_itoa(VALUE self, VALUE number, VALUE base);
|
||||
static VALUE rb_KernAux_itoa(VALUE self, VALUE number, VALUE base, VALUE prefix);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_KERNAUX_UTOA10
|
||||
static VALUE rb_KernAux_utoa10(VALUE self, VALUE number);
|
||||
#endif
|
||||
|
@ -64,11 +67,12 @@ void init_ntoa()
|
|||
rb_KernAux_Error));
|
||||
|
||||
#ifdef HAVE_KERNAUX_UTOA
|
||||
rb_define_singleton_method(rb_KernAux, "utoa", rb_KernAux_utoa, 2);
|
||||
rb_define_singleton_method(rb_KernAux, "utoa", rb_KernAux_utoa, 3);
|
||||
#endif
|
||||
#ifdef HAVE_KERNAUX_ITOA
|
||||
rb_define_singleton_method(rb_KernAux, "itoa", rb_KernAux_itoa, 2);
|
||||
rb_define_singleton_method(rb_KernAux, "itoa", rb_KernAux_itoa, 3);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_KERNAUX_UTOA10
|
||||
rb_define_singleton_method(rb_KernAux, "utoa10", rb_KernAux_utoa10, 1);
|
||||
#endif
|
||||
|
@ -87,14 +91,31 @@ void init_ntoa()
|
|||
VALUE rb_KernAux_utoa(
|
||||
const VALUE self_rb __attribute__((unused)),
|
||||
const VALUE number_rb,
|
||||
const VALUE base_rb
|
||||
const VALUE base_rb,
|
||||
VALUE prefix_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_UTOA_BUFFER_SIZE];
|
||||
kernaux_utoa(NUM2ULL(number_rb), buffer, convert_base(base_rb));
|
||||
|
||||
const char *prefix = NULL;
|
||||
long prefix_len = 0;
|
||||
if (!NIL_P(prefix_rb)) {
|
||||
prefix = StringValueCStr(prefix_rb);
|
||||
prefix_len = RSTRING_LEN(prefix_rb);
|
||||
|
||||
if (prefix_len > MAX_PREFIX_LEN || prefix_len < 0) {
|
||||
rb_raise(
|
||||
rb_eArgError,
|
||||
"prefix length %ld is too long",
|
||||
prefix_len
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
char buffer[KERNAUX_UTOA_BUFFER_SIZE + prefix_len];
|
||||
kernaux_utoa(NUM2ULL(number_rb), buffer, convert_base(base_rb), prefix);
|
||||
return rb_funcall(rb_str_new2(buffer), rb_intern_freeze, 0);
|
||||
}
|
||||
#endif
|
||||
|
@ -103,11 +124,28 @@ VALUE rb_KernAux_utoa(
|
|||
VALUE rb_KernAux_itoa(
|
||||
const VALUE self_rb __attribute__((unused)),
|
||||
const VALUE number_rb,
|
||||
const VALUE base_rb
|
||||
const VALUE base_rb,
|
||||
VALUE prefix_rb
|
||||
) {
|
||||
RB_INTEGER_TYPE_P(number_rb);
|
||||
char buffer[KERNAUX_ITOA_BUFFER_SIZE];
|
||||
kernaux_itoa(NUM2LL(number_rb), buffer, convert_base(base_rb));
|
||||
|
||||
const char *prefix = NULL;
|
||||
long prefix_len = 0;
|
||||
if (!NIL_P(prefix_rb)) {
|
||||
prefix = StringValueCStr(prefix_rb);
|
||||
prefix_len = RSTRING_LEN(prefix_rb);
|
||||
|
||||
if (prefix_len > MAX_PREFIX_LEN || prefix_len < 0) {
|
||||
rb_raise(
|
||||
rb_eArgError,
|
||||
"prefix length %ld is too long",
|
||||
prefix_len
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
char buffer[KERNAUX_ITOA_BUFFER_SIZE + prefix_len];
|
||||
kernaux_itoa(NUM2LL(number_rb), buffer, convert_base(base_rb), prefix);
|
||||
return rb_funcall(rb_str_new2(buffer), rb_intern_freeze, 0);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -4,10 +4,11 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe KernAux, '.itoa' do
|
||||
if described_class.singleton_class.method_defined? :itoa
|
||||
subject(:itoa) { described_class.itoa number, base }
|
||||
subject(:itoa) { described_class.itoa number, base, prefix }
|
||||
|
||||
let(:number) { rand((-2**63)..(2**63 - 1)) }
|
||||
let(:base) { rand 2..36 }
|
||||
let(:prefix) { [nil, ''].sample }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
|
@ -167,5 +168,63 @@ RSpec.describe KernAux, '.itoa' do
|
|||
raise_error described_class::InvalidNtoaBaseError, 'invalid base'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when prefix is nil' do
|
||||
let(:prefix) { nil }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s base }
|
||||
end
|
||||
|
||||
context 'when prefix is empty' do
|
||||
let(:prefix) { '' }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s base }
|
||||
end
|
||||
|
||||
context 'when prefix is present' do
|
||||
let(:prefix) { 'foo' }
|
||||
|
||||
def sign = number < 0 ? '-' : ''
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq "#{sign}foo#{number.abs.to_s(base)}" }
|
||||
end
|
||||
|
||||
context 'when prefix is not a string' do
|
||||
let(:prefix) { 123 }
|
||||
|
||||
specify do
|
||||
expect { itoa }.to raise_error(
|
||||
TypeError,
|
||||
"no implicit conversion of #{prefix.class} into String",
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when prefix has max length' do
|
||||
let(:prefix) { 'a' * 100 }
|
||||
|
||||
def sign = number < 0 ? '-' : ''
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq "#{sign}#{prefix}#{number.abs.to_s(base)}" }
|
||||
end
|
||||
|
||||
context 'when prefix is too long' do
|
||||
let(:prefix) { 'a' * 101 }
|
||||
|
||||
specify do
|
||||
expect { itoa }.to raise_error(
|
||||
ArgumentError,
|
||||
"prefix length #{prefix.length} is too long",
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,10 +4,11 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe KernAux, '.utoa' do
|
||||
if described_class.singleton_class.method_defined? :utoa
|
||||
subject(:utoa) { described_class.utoa number, base }
|
||||
subject(:utoa) { described_class.utoa number, base, prefix }
|
||||
|
||||
let(:number) { rand 0..(2**64 - 1) }
|
||||
let(:base) { rand 2..36 }
|
||||
let(:prefix) { [nil, ''].sample }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
|
@ -143,5 +144,59 @@ RSpec.describe KernAux, '.utoa' do
|
|||
raise_error described_class::InvalidNtoaBaseError, 'invalid base'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when prefix is nil' do
|
||||
let(:prefix) { nil }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s base }
|
||||
end
|
||||
|
||||
context 'when prefix is empty' do
|
||||
let(:prefix) { '' }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s base }
|
||||
end
|
||||
|
||||
context 'when prefix is present' do
|
||||
let(:prefix) { 'foo' }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq "#{prefix}#{number.to_s(base)}" }
|
||||
end
|
||||
|
||||
context 'when prefix is not a string' do
|
||||
let(:prefix) { 123 }
|
||||
|
||||
specify do
|
||||
expect { utoa }.to raise_error(
|
||||
TypeError,
|
||||
"no implicit conversion of #{prefix.class} into String",
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when prefix has max length' do
|
||||
let(:prefix) { 'a' * 100 }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq "#{prefix}#{number.to_s(base)}" }
|
||||
end
|
||||
|
||||
context 'when prefix is too long' do
|
||||
let(:prefix) { 'a' * 101 }
|
||||
|
||||
specify do
|
||||
expect { utoa }.to raise_error(
|
||||
ArgumentError,
|
||||
"prefix length #{prefix.length} is too long",
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,9 +10,20 @@ pub const ITOA16_BUFFER_SIZE: usize = 18;
|
|||
#[link(name = "kernaux")]
|
||||
extern "C" {
|
||||
#[link_name = "kernaux_utoa"]
|
||||
pub fn utoa(value: u64, buffer: *mut c_char, base: c_int) -> *mut c_char;
|
||||
pub fn utoa(
|
||||
value: u64,
|
||||
buffer: *mut c_char,
|
||||
base: c_int,
|
||||
prefix: *const c_char,
|
||||
) -> *mut c_char;
|
||||
#[link_name = "kernaux_itoa"]
|
||||
pub fn itoa(value: i64, buffer: *mut c_char, base: c_int) -> *mut c_char;
|
||||
pub fn itoa(
|
||||
value: i64,
|
||||
buffer: *mut c_char,
|
||||
base: c_int,
|
||||
prefix: *const c_char,
|
||||
) -> *mut c_char;
|
||||
|
||||
#[link_name = "kernaux_utoa10"]
|
||||
pub fn utoa10(value: u64, buffer: *mut c_char);
|
||||
#[link_name = "kernaux_itoa10"]
|
||||
|
@ -27,36 +38,105 @@ extern "C" {
|
|||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::ptr::null;
|
||||
|
||||
fn empty_prefix() -> CString {
|
||||
CString::new("").unwrap()
|
||||
}
|
||||
|
||||
fn foo_prefix() -> CString {
|
||||
CString::new("foo").unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_utoa() {
|
||||
let mut buffer: [i8; UTOA_BUFFER_SIZE] = [0; UTOA_BUFFER_SIZE];
|
||||
let mut buffer: [i8; UTOA_BUFFER_SIZE + 3] = [0; UTOA_BUFFER_SIZE + 3];
|
||||
|
||||
let empty_pfx = empty_prefix();
|
||||
let foo_pfx = foo_prefix();
|
||||
|
||||
let end: *mut c_char =
|
||||
unsafe { utoa(0x123, buffer.as_mut_ptr(), 'x' as c_int) };
|
||||
unsafe { utoa(0x123, buffer.as_mut_ptr(), 'x' as c_int, null()) };
|
||||
let result =
|
||||
unsafe { CStr::from_ptr(buffer.as_ptr()) }.to_str().unwrap();
|
||||
assert_eq!(result, "123");
|
||||
assert_eq!(end, unsafe { buffer.as_mut_ptr().offset(3) });
|
||||
|
||||
let end: *mut c_char = unsafe {
|
||||
utoa(0x123, buffer.as_mut_ptr(), 'x' as c_int, empty_pfx.as_ptr())
|
||||
};
|
||||
let result =
|
||||
unsafe { CStr::from_ptr(buffer.as_ptr()) }.to_str().unwrap();
|
||||
assert_eq!(result, "123");
|
||||
assert_eq!(end, unsafe { buffer.as_mut_ptr().offset(3) });
|
||||
|
||||
let end: *mut c_char = unsafe {
|
||||
utoa(0x123, buffer.as_mut_ptr(), 'x' as c_int, foo_pfx.as_ptr())
|
||||
};
|
||||
let result =
|
||||
unsafe { CStr::from_ptr(buffer.as_ptr()) }.to_str().unwrap();
|
||||
assert_eq!(result, "foo123");
|
||||
assert_eq!(end, unsafe { buffer.as_mut_ptr().offset(6) });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_itoa() {
|
||||
let mut buffer: [i8; ITOA_BUFFER_SIZE] = [0; ITOA_BUFFER_SIZE];
|
||||
let mut buffer: [i8; ITOA_BUFFER_SIZE + 3] = [0; ITOA_BUFFER_SIZE + 3];
|
||||
|
||||
let empty_pfx = empty_prefix();
|
||||
let foo_pfx = foo_prefix();
|
||||
|
||||
let end: *mut c_char =
|
||||
unsafe { itoa(0x123, buffer.as_mut_ptr(), 'x' as c_int) };
|
||||
unsafe { itoa(0x123, buffer.as_mut_ptr(), 'x' as c_int, null()) };
|
||||
let result =
|
||||
unsafe { CStr::from_ptr(buffer.as_ptr()) }.to_str().unwrap();
|
||||
assert_eq!(result, "123");
|
||||
assert_eq!(end, unsafe { buffer.as_mut_ptr().offset(3) });
|
||||
|
||||
let mut buffer: [i8; 1000] = [0; 1000];
|
||||
let end: *mut c_char = unsafe {
|
||||
itoa(0x123, buffer.as_mut_ptr(), 'x' as c_int, empty_pfx.as_ptr())
|
||||
};
|
||||
let result =
|
||||
unsafe { CStr::from_ptr(buffer.as_ptr()) }.to_str().unwrap();
|
||||
assert_eq!(result, "123");
|
||||
assert_eq!(end, unsafe { buffer.as_mut_ptr().offset(3) });
|
||||
|
||||
let end: *mut c_char = unsafe {
|
||||
itoa(0x123, buffer.as_mut_ptr(), 'x' as c_int, foo_pfx.as_ptr())
|
||||
};
|
||||
let result =
|
||||
unsafe { CStr::from_ptr(buffer.as_ptr()) }.to_str().unwrap();
|
||||
assert_eq!(result, "foo123");
|
||||
assert_eq!(end, unsafe { buffer.as_mut_ptr().offset(6) });
|
||||
|
||||
let end: *mut c_char =
|
||||
unsafe { itoa(-0x123, buffer.as_mut_ptr(), 'x' as c_int) };
|
||||
unsafe { itoa(-0x123, buffer.as_mut_ptr(), 'x' as c_int, null()) };
|
||||
let result =
|
||||
unsafe { CStr::from_ptr(buffer.as_ptr()) }.to_str().unwrap();
|
||||
assert_eq!(result, "-123");
|
||||
assert_eq!(end, unsafe { buffer.as_mut_ptr().offset(4) });
|
||||
|
||||
let end: *mut c_char = unsafe {
|
||||
itoa(
|
||||
-0x123,
|
||||
buffer.as_mut_ptr(),
|
||||
'x' as c_int,
|
||||
empty_pfx.as_ptr(),
|
||||
)
|
||||
};
|
||||
let result =
|
||||
unsafe { CStr::from_ptr(buffer.as_ptr()) }.to_str().unwrap();
|
||||
assert_eq!(result, "-123");
|
||||
assert_eq!(end, unsafe { buffer.as_mut_ptr().offset(4) });
|
||||
|
||||
let end: *mut c_char = unsafe {
|
||||
itoa(-0x123, buffer.as_mut_ptr(), 'x' as c_int, foo_pfx.as_ptr())
|
||||
};
|
||||
let result =
|
||||
unsafe { CStr::from_ptr(buffer.as_ptr()) }.to_str().unwrap();
|
||||
assert_eq!(result, "-foo123");
|
||||
assert_eq!(end, unsafe { buffer.as_mut_ptr().offset(7) });
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
23
src/ntoa.c
23
src/ntoa.c
|
@ -7,7 +7,7 @@
|
|||
|
||||
#include <stddef.h>
|
||||
|
||||
char *kernaux_utoa(uint64_t value, char *buffer, int base)
|
||||
char *kernaux_utoa(uint64_t value, char *buffer, int base, const char *prefix)
|
||||
{
|
||||
KERNAUX_NOTNULL_RETVAL(buffer, NULL);
|
||||
|
||||
|
@ -28,7 +28,10 @@ char *kernaux_utoa(uint64_t value, char *buffer, int base)
|
|||
|
||||
KERNAUX_ASSERT_RETVAL(base >= 2 && base <= 36, NULL);
|
||||
|
||||
// Write to buffer
|
||||
// Write prefix
|
||||
if (prefix) while (*prefix) *(buffer++) = *(prefix++);
|
||||
|
||||
// Write number
|
||||
char *pos = buffer;
|
||||
if (value == 0) *(pos++) = '0';
|
||||
while (value > 0) {
|
||||
|
@ -39,7 +42,7 @@ char *kernaux_utoa(uint64_t value, char *buffer, int base)
|
|||
char *const result = pos;
|
||||
*(pos--) = '\0';
|
||||
|
||||
// Reverse buffer
|
||||
// Reverse number
|
||||
while (buffer < pos) {
|
||||
const char tmp = *buffer;
|
||||
*(buffer++) = *pos;
|
||||
|
@ -49,32 +52,32 @@ char *kernaux_utoa(uint64_t value, char *buffer, int base)
|
|||
return result;
|
||||
}
|
||||
|
||||
char *kernaux_itoa(int64_t value, char *buffer, int base)
|
||||
char *kernaux_itoa(int64_t value, char *buffer, int base, const char *const prefix)
|
||||
{
|
||||
if (value >= 0) {
|
||||
return kernaux_utoa(value, buffer, base);
|
||||
return kernaux_utoa(value, buffer, base, prefix);
|
||||
} else {
|
||||
*(buffer++) = '-';
|
||||
return kernaux_utoa(-value, buffer, base);
|
||||
return kernaux_utoa(-value, buffer, base, prefix);
|
||||
}
|
||||
}
|
||||
|
||||
void kernaux_utoa10(uint64_t value, char *buffer)
|
||||
{
|
||||
kernaux_utoa(value, buffer, 'd');
|
||||
kernaux_utoa(value, buffer, 'd', NULL);
|
||||
}
|
||||
|
||||
void kernaux_itoa10(int64_t value, char *buffer)
|
||||
{
|
||||
kernaux_itoa(value, buffer, 'd');
|
||||
kernaux_itoa(value, buffer, 'd', NULL);
|
||||
}
|
||||
|
||||
void kernaux_utoa16(uint64_t value, char *buffer)
|
||||
{
|
||||
kernaux_utoa(value, buffer, 'x');
|
||||
kernaux_utoa(value, buffer, 'x', NULL);
|
||||
}
|
||||
|
||||
void kernaux_itoa16(int64_t value, char *buffer)
|
||||
{
|
||||
kernaux_itoa(value, buffer, 'x');
|
||||
kernaux_itoa(value, buffer, 'x', NULL);
|
||||
}
|
||||
|
|
|
@ -378,14 +378,14 @@ static void assert_cb(
|
|||
|
||||
static void test_utoa_assert(char *const buffer, const int base)
|
||||
{
|
||||
assert(kernaux_utoa(0, buffer, base) == NULL);
|
||||
assert(kernaux_utoa(0, buffer, base, NULL) == NULL);
|
||||
assert(assert_count_ctr == ++assert_count_exp);
|
||||
assert(strstr(assert_last_file, "src/ntoa.c") != NULL);
|
||||
}
|
||||
|
||||
static void test_itoa_assert(char *const buffer, const int base)
|
||||
{
|
||||
assert(kernaux_itoa(0, buffer, base) == NULL);
|
||||
assert(kernaux_itoa(0, buffer, base, NULL) == NULL);
|
||||
assert(assert_count_ctr == ++assert_count_exp);
|
||||
assert(strstr(assert_last_file, "src/ntoa.c") != NULL);
|
||||
}
|
||||
|
@ -422,25 +422,45 @@ int main()
|
|||
}
|
||||
|
||||
{
|
||||
char buffer[KERNAUX_UTOA_BUFFER_SIZE];
|
||||
char buffer[KERNAUX_UTOA_BUFFER_SIZE + 3];
|
||||
|
||||
for (
|
||||
size_t index = 0;
|
||||
index < sizeof(utoa_cases) / sizeof(utoa_cases[0]);
|
||||
++index
|
||||
) {
|
||||
const char *const end = kernaux_utoa(
|
||||
const char *const end1 = kernaux_utoa(
|
||||
utoa_cases[index].value,
|
||||
buffer,
|
||||
utoa_cases[index].base
|
||||
utoa_cases[index].base,
|
||||
NULL
|
||||
);
|
||||
assert(strcmp(buffer, utoa_cases[index].result) == 0);
|
||||
assert(end == str_end(buffer));
|
||||
assert(end1 == str_end(buffer));
|
||||
|
||||
const char *const end2 = kernaux_utoa(
|
||||
utoa_cases[index].value,
|
||||
buffer,
|
||||
utoa_cases[index].base,
|
||||
""
|
||||
);
|
||||
assert(strcmp(buffer, utoa_cases[index].result) == 0);
|
||||
assert(end2 == str_end(buffer));
|
||||
|
||||
const char *const end3 = kernaux_utoa(
|
||||
utoa_cases[index].value,
|
||||
buffer,
|
||||
utoa_cases[index].base,
|
||||
"foo"
|
||||
);
|
||||
assert(strncmp(buffer, "foo", 3) == 0);
|
||||
assert(strcmp(&buffer[3], utoa_cases[index].result) == 0);
|
||||
assert(end3 == str_end(buffer));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[KERNAUX_ITOA_BUFFER_SIZE];
|
||||
char buffer[KERNAUX_ITOA_BUFFER_SIZE + 3];
|
||||
|
||||
for (
|
||||
size_t index = 0;
|
||||
|
@ -452,16 +472,35 @@ int main()
|
|||
const int64_t value = utoa_cases[index].value;
|
||||
const int base = utoa_cases[index].base;
|
||||
|
||||
const char *const end1 = kernaux_itoa(value, buffer, base);
|
||||
const char *const end1 = kernaux_itoa(value, buffer, base, NULL);
|
||||
assert(strcmp(buffer, utoa_cases[index].result) == 0);
|
||||
assert(end1 == str_end(buffer));
|
||||
|
||||
const char *const end2 = kernaux_itoa(value, buffer, base, "");
|
||||
assert(strcmp(buffer, utoa_cases[index].result) == 0);
|
||||
assert(end2 == str_end(buffer));
|
||||
|
||||
const char *const end3 = kernaux_itoa(value, buffer, base, "foo");
|
||||
assert(strncmp(buffer, "foo", 3) == 0);
|
||||
assert(strcmp(&buffer[3], utoa_cases[index].result) == 0);
|
||||
assert(end3 == str_end(buffer));
|
||||
|
||||
if (value <= 0 || base < 2 || base > 36) continue;
|
||||
|
||||
const char *const end2 = kernaux_itoa(-value, buffer, base);
|
||||
const char *const end4 = kernaux_itoa(-value, buffer, base, NULL);
|
||||
assert(buffer[0] == '-');
|
||||
assert(strcmp(&buffer[1], utoa_cases[index].result) == 0);
|
||||
assert(end2 == str_end(buffer));
|
||||
assert(end4 == str_end(buffer));
|
||||
|
||||
const char *const end5 = kernaux_itoa(-value, buffer, base, "");
|
||||
assert(buffer[0] == '-');
|
||||
assert(strcmp(&buffer[1], utoa_cases[index].result) == 0);
|
||||
assert(end5 == str_end(buffer));
|
||||
|
||||
const char *const end6 = kernaux_itoa(-value, buffer, base, "foo");
|
||||
assert(strncmp(buffer, "-foo", 4) == 0);
|
||||
assert(strcmp(&buffer[4], utoa_cases[index].result) == 0);
|
||||
assert(end6 == str_end(buffer));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue