mirror of
https://github.com/tailix/libkernaux.git
synced 2024-10-30 11:54:01 -04:00
Ruby: Add methods KernAux.utoa, .itoa
This commit is contained in:
parent
3d677837cf
commit
33eb48ddb0
6 changed files with 429 additions and 1 deletions
|
@ -44,7 +44,7 @@ void init_cmdline()
|
|||
|
||||
rb_gc_register_mark_object(rb_KernAux = rb_define_module("KernAux"));
|
||||
rb_gc_register_mark_object(rb_KernAux_Error =
|
||||
rb_define_class_under(rb_KernAux, "Error" ,rb_eRuntimeError));
|
||||
rb_define_class_under(rb_KernAux, "Error", rb_eRuntimeError));
|
||||
rb_gc_register_mark_object(rb_KernAux_CmdlineError =
|
||||
rb_define_class_under(rb_KernAux, "CmdlineError", rb_KernAux_Error));
|
||||
rb_gc_register_mark_object(rb_ANON_Data =
|
||||
|
|
|
@ -11,6 +11,8 @@ unless have_var 'kernaux_assert_cb', 'kernaux.h'
|
|||
raise 'kernaux_assert_cb not found'
|
||||
end
|
||||
|
||||
have_func 'kernaux_utoa'
|
||||
have_func 'kernaux_itoa'
|
||||
have_func 'kernaux_utoa10'
|
||||
have_func 'kernaux_itoa10'
|
||||
have_func 'kernaux_utoa16'
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
#include <kernaux.h>
|
||||
#include <ruby.h>
|
||||
|
||||
#ifdef HAVE_KERNAUX_UTOA
|
||||
static VALUE rb_KernAux_utoa(VALUE self, VALUE number, VALUE base);
|
||||
#endif
|
||||
#ifdef HAVE_KERNAUX_ITOA
|
||||
static VALUE rb_KernAux_itoa(VALUE self, VALUE number, VALUE base);
|
||||
#endif
|
||||
#ifdef HAVE_KERNAUX_UTOA10
|
||||
static VALUE rb_KernAux_utoa10(VALUE self, VALUE number);
|
||||
#endif
|
||||
|
@ -15,17 +21,50 @@ static VALUE rb_KernAux_itoa16(VALUE self, VALUE number);
|
|||
#endif
|
||||
|
||||
static ID rb_intern_LESS = Qnil;
|
||||
static ID rb_intern_b = Qnil;
|
||||
static ID rb_intern_B = Qnil;
|
||||
static ID rb_intern_freeze = Qnil;
|
||||
static ID rb_intern_h = Qnil;
|
||||
static ID rb_intern_H = Qnil;
|
||||
static ID rb_intern_o = Qnil;
|
||||
static ID rb_intern_O = Qnil;
|
||||
static ID rb_intern_d = Qnil;
|
||||
static ID rb_intern_D = Qnil;
|
||||
static ID rb_intern_x = Qnil;
|
||||
static ID rb_intern_X = Qnil;
|
||||
|
||||
static VALUE rb_KernAux = Qnil;
|
||||
static VALUE rb_KernAux_Error = Qnil;
|
||||
static VALUE rb_KernAux_InvalidNtoaBaseError = Qnil;
|
||||
|
||||
void init_ntoa()
|
||||
{
|
||||
rb_gc_register_mark_object(ID2SYM(rb_intern_LESS = rb_intern("<")));
|
||||
rb_gc_register_mark_object(ID2SYM(rb_intern_b = rb_intern("b")));
|
||||
rb_gc_register_mark_object(ID2SYM(rb_intern_B = rb_intern("B")));
|
||||
rb_gc_register_mark_object(ID2SYM(rb_intern_freeze = rb_intern("freeze")));
|
||||
rb_gc_register_mark_object(ID2SYM(rb_intern_h = rb_intern("h")));
|
||||
rb_gc_register_mark_object(ID2SYM(rb_intern_H = rb_intern("H")));
|
||||
rb_gc_register_mark_object(ID2SYM(rb_intern_o = rb_intern("o")));
|
||||
rb_gc_register_mark_object(ID2SYM(rb_intern_O = rb_intern("O")));
|
||||
rb_gc_register_mark_object(ID2SYM(rb_intern_d = rb_intern("d")));
|
||||
rb_gc_register_mark_object(ID2SYM(rb_intern_D = rb_intern("D")));
|
||||
rb_gc_register_mark_object(ID2SYM(rb_intern_x = rb_intern("x")));
|
||||
rb_gc_register_mark_object(ID2SYM(rb_intern_X = rb_intern("X")));
|
||||
|
||||
rb_gc_register_mark_object(rb_KernAux = rb_define_module("KernAux"));
|
||||
rb_gc_register_mark_object(rb_KernAux_Error =
|
||||
rb_define_class_under(rb_KernAux, "Error", rb_eRuntimeError));
|
||||
rb_gc_register_mark_object(rb_KernAux_InvalidNtoaBaseError =
|
||||
rb_define_class_under(rb_KernAux, "InvalidNtoaBaseError",
|
||||
rb_KernAux_Error));
|
||||
|
||||
#ifdef HAVE_KERNAUX_UTOA
|
||||
rb_define_singleton_method(rb_KernAux, "utoa", rb_KernAux_utoa, 2);
|
||||
#endif
|
||||
#ifdef HAVE_KERNAUX_ITOA
|
||||
rb_define_singleton_method(rb_KernAux, "itoa", rb_KernAux_itoa, 2);
|
||||
#endif
|
||||
#ifdef HAVE_KERNAUX_UTOA10
|
||||
rb_define_singleton_method(rb_KernAux, "utoa10", rb_KernAux_utoa10, 1);
|
||||
#endif
|
||||
|
@ -40,6 +79,77 @@ void init_ntoa()
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_KERNAUX_UTOA
|
||||
VALUE rb_KernAux_utoa(
|
||||
const VALUE self_rb __attribute__((unused)),
|
||||
const VALUE number_rb,
|
||||
const VALUE base_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");
|
||||
}
|
||||
|
||||
int base = 0;
|
||||
if (TYPE(base_rb) == T_SYMBOL) {
|
||||
const ID base_id = SYM2ID(base_rb);
|
||||
if (base_id == rb_intern_b) base = 'b';
|
||||
else if (base_id == rb_intern_B) base = 'B';
|
||||
else if (base_id == rb_intern_h) base = 'h';
|
||||
else if (base_id == rb_intern_H) base = 'H';
|
||||
else if (base_id == rb_intern_o) base = 'o';
|
||||
else if (base_id == rb_intern_O) base = 'O';
|
||||
else if (base_id == rb_intern_d) base = 'd';
|
||||
else if (base_id == rb_intern_D) base = 'D';
|
||||
else if (base_id == rb_intern_x) base = 'x';
|
||||
else if (base_id == rb_intern_X) base = 'X';
|
||||
else {
|
||||
rb_raise(rb_KernAux_InvalidNtoaBaseError, "invalid base");
|
||||
}
|
||||
} else {
|
||||
base = NUM2INT(base_rb);
|
||||
}
|
||||
|
||||
char buffer[KERNAUX_UTOA_BUFFER_SIZE];
|
||||
kernaux_utoa(NUM2ULL(number_rb), buffer, base);
|
||||
return rb_funcall(rb_str_new2(buffer), rb_intern_freeze, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_KERNAUX_ITOA
|
||||
VALUE rb_KernAux_itoa(
|
||||
const VALUE self_rb __attribute__((unused)),
|
||||
const VALUE number_rb,
|
||||
const VALUE base_rb
|
||||
) {
|
||||
RB_INTEGER_TYPE_P(number_rb);
|
||||
|
||||
int base = 0;
|
||||
if (TYPE(base_rb) == T_SYMBOL) {
|
||||
const ID base_id = SYM2ID(base_rb);
|
||||
if (base_id == rb_intern_b) base = 'b';
|
||||
else if (base_id == rb_intern_B) base = 'B';
|
||||
else if (base_id == rb_intern_h) base = 'h';
|
||||
else if (base_id == rb_intern_H) base = 'H';
|
||||
else if (base_id == rb_intern_o) base = 'o';
|
||||
else if (base_id == rb_intern_O) base = 'O';
|
||||
else if (base_id == rb_intern_d) base = 'd';
|
||||
else if (base_id == rb_intern_D) base = 'D';
|
||||
else if (base_id == rb_intern_x) base = 'x';
|
||||
else if (base_id == rb_intern_X) base = 'X';
|
||||
else {
|
||||
rb_raise(rb_KernAux_InvalidNtoaBaseError, "invalid base");
|
||||
}
|
||||
} else {
|
||||
base = NUM2INT(base_rb);
|
||||
}
|
||||
|
||||
char buffer[KERNAUX_ITOA_BUFFER_SIZE];
|
||||
kernaux_itoa(NUM2LL(number_rb), buffer, base);
|
||||
return rb_funcall(rb_str_new2(buffer), rb_intern_freeze, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_KERNAUX_UTOA10
|
||||
VALUE rb_KernAux_utoa10(
|
||||
const VALUE self_rb __attribute__((unused)),
|
||||
|
|
|
@ -55,4 +55,12 @@ module KernAux
|
|||
# @see .cmdline
|
||||
#
|
||||
class CmdlineError < Error; end
|
||||
|
||||
##
|
||||
# Raised when {.utoa} or {.itoa} base is invalid.
|
||||
#
|
||||
# @see .utoa
|
||||
# @see .itoa
|
||||
#
|
||||
class InvalidNtoaBaseError < Error; end
|
||||
end
|
||||
|
|
161
pkgs/ruby/spec/lib/kernaux/itoa_spec.rb
Normal file
161
pkgs/ruby/spec/lib/kernaux/itoa_spec.rb
Normal file
|
@ -0,0 +1,161 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe KernAux, '.itoa' do
|
||||
if described_class.singleton_class.method_defined? :itoa
|
||||
subject(:itoa) { described_class.itoa number, base }
|
||||
|
||||
let(:number) { rand((-2**63)..(2**63 - 1)) }
|
||||
let(:base) { rand 2..36 }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s base }
|
||||
|
||||
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 base }
|
||||
end
|
||||
|
||||
context 'when number is max int64_t' do
|
||||
let(:number) { 2**63 - 1 }
|
||||
|
||||
it { is_expected.to eq number.to_s base }
|
||||
end
|
||||
|
||||
context 'when number is lesser than min uint64_t' do
|
||||
let(:number) { -2**63 - 1 }
|
||||
|
||||
specify do
|
||||
expect { itoa }.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 { itoa }.to raise_error \
|
||||
RangeError, 'bignum too big to convert into `long long\''
|
||||
end
|
||||
end
|
||||
|
||||
context 'when base is negative' do
|
||||
let(:base) { -rand(2..36) }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s(-base).upcase }
|
||||
end
|
||||
|
||||
context 'when base is :b' do
|
||||
let(:base) { :b }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s 2 }
|
||||
end
|
||||
|
||||
context 'when base is :B:' do
|
||||
let(:base) { :B }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s 2 }
|
||||
end
|
||||
|
||||
context 'when base is :o' do
|
||||
let(:base) { :o }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s 8 }
|
||||
end
|
||||
|
||||
context 'when base is :O' do
|
||||
let(:base) { :O }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s 8 }
|
||||
end
|
||||
|
||||
context 'when base is :d' do
|
||||
let(:base) { :d }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s }
|
||||
end
|
||||
|
||||
context 'when base is :D' do
|
||||
let(:base) { :D }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s }
|
||||
end
|
||||
|
||||
context 'when base is :h' do
|
||||
let(:base) { :h }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s 16 }
|
||||
end
|
||||
|
||||
context 'when base is :x' do
|
||||
let(:base) { :x }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s 16 }
|
||||
end
|
||||
|
||||
context 'when base is :H' do
|
||||
let(:base) { :H }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s(16).upcase }
|
||||
end
|
||||
|
||||
context 'when base is :X' do
|
||||
let(:base) { :X }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s(16).upcase }
|
||||
end
|
||||
|
||||
context 'when base is an invalid symbol' do
|
||||
let(:base) { :foo }
|
||||
|
||||
specify do
|
||||
expect { itoa }.to \
|
||||
raise_error described_class::InvalidNtoaBaseError, 'invalid base'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
147
pkgs/ruby/spec/lib/kernaux/utoa_spec.rb
Normal file
147
pkgs/ruby/spec/lib/kernaux/utoa_spec.rb
Normal file
|
@ -0,0 +1,147 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe KernAux, '.utoa' do
|
||||
if described_class.singleton_class.method_defined? :utoa
|
||||
subject(:utoa) { described_class.utoa number, base }
|
||||
|
||||
let(:number) { rand 0..(2**64 - 1) }
|
||||
let(:base) { rand 2..36 }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s base }
|
||||
|
||||
context 'when number is 0' do
|
||||
let(:number) { 0 }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq '0' }
|
||||
end
|
||||
|
||||
context 'when number is max uint64_t' do
|
||||
let(:number) { 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 base }
|
||||
end
|
||||
|
||||
context 'when number is -1' do
|
||||
let(:number) { -1 }
|
||||
|
||||
specify do
|
||||
expect { utoa }.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 { utoa }.to raise_error \
|
||||
RangeError, 'bignum too big to convert into `unsigned long long\''
|
||||
end
|
||||
end
|
||||
|
||||
context 'when base is negative' do
|
||||
let(:base) { -rand(2..36) }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s(-base).upcase }
|
||||
end
|
||||
|
||||
context 'when base is :b' do
|
||||
let(:base) { :b }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s 2 }
|
||||
end
|
||||
|
||||
context 'when base is :B:' do
|
||||
let(:base) { :B }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s 2 }
|
||||
end
|
||||
|
||||
context 'when base is :o' do
|
||||
let(:base) { :o }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s 8 }
|
||||
end
|
||||
|
||||
context 'when base is :O' do
|
||||
let(:base) { :O }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s 8 }
|
||||
end
|
||||
|
||||
context 'when base is :d' do
|
||||
let(:base) { :d }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s }
|
||||
end
|
||||
|
||||
context 'when base is :D' do
|
||||
let(:base) { :D }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s }
|
||||
end
|
||||
|
||||
context 'when base is :h' do
|
||||
let(:base) { :h }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s 16 }
|
||||
end
|
||||
|
||||
context 'when base is :x' do
|
||||
let(:base) { :x }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s 16 }
|
||||
end
|
||||
|
||||
context 'when base is :H' do
|
||||
let(:base) { :H }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s(16).upcase }
|
||||
end
|
||||
|
||||
context 'when base is :X' do
|
||||
let(:base) { :X }
|
||||
|
||||
it { is_expected.to be_instance_of String }
|
||||
it { is_expected.to be_frozen }
|
||||
it { is_expected.to eq number.to_s(16).upcase }
|
||||
end
|
||||
|
||||
context 'when base is an invalid symbol' do
|
||||
let(:base) { :foo }
|
||||
|
||||
specify do
|
||||
expect { utoa }.to \
|
||||
raise_error described_class::InvalidNtoaBaseError, 'invalid base'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue