* rational.c (rb_flt_rationalize_with_prec): new public C function
to rationalize a Float instance with a precision. * rational.c (rb_flt_rationalize): new public C function to rationalize a Float instance. A precision is calculated from the given float number. * include/ruby/intern.h: Add rb_flt_rationalize_with_prec and rb_flt_rationalize. * parse.y: implement number literal suffixes, 'r' and 'i'. [ruby-core:55096] [Feature #8430] * bootstraptest/test_literal_suffix.rb: add tests for parser to scan number literals with the above tsuffixes. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42311 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
9ebd675c47
commit
e06407cf7d
18
ChangeLog
18
ChangeLog
@ -1,3 +1,21 @@
|
|||||||
|
Thu Aug 1 23:45:00 2013 Kenta Murata <mrkn@mrkn.jp>
|
||||||
|
|
||||||
|
* rational.c (rb_flt_rationalize_with_prec): new public C function
|
||||||
|
to rationalize a Float instance with a precision.
|
||||||
|
|
||||||
|
* rational.c (rb_flt_rationalize): new public C function to
|
||||||
|
rationalize a Float instance. A precision is calculated from
|
||||||
|
the given float number.
|
||||||
|
|
||||||
|
* include/ruby/intern.h: Add rb_flt_rationalize_with_prec and
|
||||||
|
rb_flt_rationalize.
|
||||||
|
|
||||||
|
* parse.y: implement number literal suffixes, 'r' and 'i'.
|
||||||
|
[ruby-core:55096] [Feature #8430]
|
||||||
|
|
||||||
|
* bootstraptest/test_literal_suffix.rb: add tests for parser to scan
|
||||||
|
number literals with the above tsuffixes.
|
||||||
|
|
||||||
Thu Aug 1 23:55:08 2013 Tanaka Akira <akr@fsij.org>
|
Thu Aug 1 23:55:08 2013 Tanaka Akira <akr@fsij.org>
|
||||||
|
|
||||||
* bignum.c (rb_big2str1): Remove a local variable.
|
* bignum.c (rb_big2str1): Remove a local variable.
|
||||||
|
46
bootstraptest/test_literal_suffix.rb
Normal file
46
bootstraptest/test_literal_suffix.rb
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# numbers with suffix
|
||||||
|
assert_equal '0/1', '0r'
|
||||||
|
assert_equal 'Rational', '0r.class'
|
||||||
|
assert_equal '1/1', '1r'
|
||||||
|
assert_equal 'Rational', '1r.class'
|
||||||
|
assert_equal '1/1', '0x1r'
|
||||||
|
assert_equal 'Rational', '0x1r.class'
|
||||||
|
assert_equal '1/1', '0b1r'
|
||||||
|
assert_equal 'Rational', '0b1r.class'
|
||||||
|
assert_equal '1/1', '0d1r'
|
||||||
|
assert_equal 'Rational', '0d1r.class'
|
||||||
|
assert_equal '1/1', '0o1r'
|
||||||
|
assert_equal 'Rational', '0o1r.class'
|
||||||
|
assert_equal '1/1', '01r'
|
||||||
|
assert_equal 'Rational', '01r.class'
|
||||||
|
assert_equal '6/5', '1.2r'
|
||||||
|
assert_equal 'Rational', '1.2r.class'
|
||||||
|
assert_equal '0+0i', '0i'
|
||||||
|
assert_equal 'Complex', '0i.class'
|
||||||
|
assert_equal '0+1i', '1i'
|
||||||
|
assert_equal 'Complex', '1i.class'
|
||||||
|
assert_equal '0+1i', '0x1i'
|
||||||
|
assert_equal 'Complex', '0x1i.class'
|
||||||
|
assert_equal '0+1i', '0b1i'
|
||||||
|
assert_equal 'Complex', '0b1i.class'
|
||||||
|
assert_equal '0+1i', '0d1i'
|
||||||
|
assert_equal 'Complex', '0d1i.class'
|
||||||
|
assert_equal '0+1i', '0o1i'
|
||||||
|
assert_equal 'Complex', '0o1i.class'
|
||||||
|
assert_equal '0+1i', '01i'
|
||||||
|
assert_equal 'Complex', '01i.class'
|
||||||
|
assert_equal '0+1.2i', '1.2i'
|
||||||
|
assert_equal 'Complex', '1.2i.class'
|
||||||
|
assert_equal '0+1/1i', '1ri'
|
||||||
|
assert_equal 'Complex', '1ri.class'
|
||||||
|
assert_equal '0+6/5i', '1.2ri'
|
||||||
|
assert_equal 'Complex', '1.2ri.class'
|
||||||
|
assert_equal '0+10.0i', '1e1i'
|
||||||
|
assert_equal 'Complex', '1e1i.class'
|
||||||
|
|
||||||
|
assert_equal 'syntax error, unexpected tIDENTIFIER, expecting end-of-input',
|
||||||
|
%q{begin eval('1ir', nil, '', 0); rescue SyntaxError => e; e.message[/\A:(?:\d+:)? (.*)/, 1] end}
|
||||||
|
assert_equal 'syntax error, unexpected tIDENTIFIER, expecting end-of-input',
|
||||||
|
%q{begin eval('1.2ir', nil, '', 0); rescue SyntaxError => e; e.message[/\A:(?:\d+:)? (.*)/, 1] end}
|
||||||
|
assert_equal 'syntax error, unexpected tIDENTIFIER, expecting end-of-input',
|
||||||
|
%q{begin eval('1e1r', nil, '', 0); rescue SyntaxError => e; e.message[/\A:(?:\d+:)? (.*)/, 1] end}
|
@ -171,6 +171,8 @@ VALUE rb_rational_new(VALUE, VALUE);
|
|||||||
VALUE rb_Rational(VALUE, VALUE);
|
VALUE rb_Rational(VALUE, VALUE);
|
||||||
#define rb_Rational1(x) rb_Rational((x), INT2FIX(1))
|
#define rb_Rational1(x) rb_Rational((x), INT2FIX(1))
|
||||||
#define rb_Rational2(x,y) rb_Rational((x), (y))
|
#define rb_Rational2(x,y) rb_Rational((x), (y))
|
||||||
|
VALUE rb_flt_rationalize_with_prec(VALUE, VALUE);
|
||||||
|
VALUE rb_flt_rationalize(VALUE);
|
||||||
/* complex.c */
|
/* complex.c */
|
||||||
VALUE rb_complex_raw(VALUE, VALUE);
|
VALUE rb_complex_raw(VALUE, VALUE);
|
||||||
#define rb_complex_raw1(x) rb_complex_raw((x), INT2FIX(0))
|
#define rb_complex_raw1(x) rb_complex_raw((x), INT2FIX(0))
|
||||||
|
119
parse.y
119
parse.y
@ -754,7 +754,7 @@ static void token_info_pop(struct parser_params*, const char *token);
|
|||||||
keyword__ENCODING__
|
keyword__ENCODING__
|
||||||
|
|
||||||
%token <id> tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL
|
%token <id> tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL
|
||||||
%token <node> tINTEGER tFLOAT tSTRING_CONTENT tCHAR
|
%token <node> tINTEGER tFLOAT tRATIONAL tIMAGINARY tSTRING_CONTENT tCHAR
|
||||||
%token <node> tNTH_REF tBACK_REF
|
%token <node> tNTH_REF tBACK_REF
|
||||||
%token <num> tREGEXP_END
|
%token <num> tREGEXP_END
|
||||||
|
|
||||||
@ -2128,6 +2128,24 @@ arg : lhs '=' arg
|
|||||||
$$ = dispatch2(unary, ripper_intern("-@"), $$);
|
$$ = dispatch2(unary, ripper_intern("-@"), $$);
|
||||||
%*/
|
%*/
|
||||||
}
|
}
|
||||||
|
| tUMINUS_NUM tRATIONAL tPOW arg
|
||||||
|
{
|
||||||
|
/*%%%*/
|
||||||
|
$$ = NEW_CALL(call_bin_op($2, tPOW, $4), tUMINUS, 0);
|
||||||
|
/*%
|
||||||
|
$$ = dispatch3(binary, $2, ripper_intern("**"), $4);
|
||||||
|
$$ = dispatch2(unary, ripper_intern("-@"), $$);
|
||||||
|
%*/
|
||||||
|
}
|
||||||
|
| tUMINUS_NUM tIMAGINARY tPOW arg
|
||||||
|
{
|
||||||
|
/*%%%*/
|
||||||
|
$$ = NEW_CALL(call_bin_op($2, tPOW, $4), tUMINUS, 0);
|
||||||
|
/*%
|
||||||
|
$$ = dispatch3(binary, $2, ripper_intern("**"), $4);
|
||||||
|
$$ = dispatch2(unary, ripper_intern("-@"), $$);
|
||||||
|
%*/
|
||||||
|
}
|
||||||
| tUPLUS arg
|
| tUPLUS arg
|
||||||
{
|
{
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
@ -4294,6 +4312,8 @@ dsym : tSYMBEG xstring_contents tSTRING_END
|
|||||||
|
|
||||||
numeric : tINTEGER
|
numeric : tINTEGER
|
||||||
| tFLOAT
|
| tFLOAT
|
||||||
|
| tRATIONAL
|
||||||
|
| tIMAGINARY
|
||||||
| tUMINUS_NUM tINTEGER %prec tLOWEST
|
| tUMINUS_NUM tINTEGER %prec tLOWEST
|
||||||
{
|
{
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
@ -4310,6 +4330,22 @@ numeric : tINTEGER
|
|||||||
$$ = dispatch2(unary, ripper_intern("-@"), $2);
|
$$ = dispatch2(unary, ripper_intern("-@"), $2);
|
||||||
%*/
|
%*/
|
||||||
}
|
}
|
||||||
|
| tUMINUS_NUM tRATIONAL %prec tLOWEST
|
||||||
|
{
|
||||||
|
/*%%%*/
|
||||||
|
$$ = negate_lit($2);
|
||||||
|
/*%
|
||||||
|
$$ = dispatch2(unary, ripper_intern("-@"), $2);
|
||||||
|
%*/
|
||||||
|
}
|
||||||
|
| tUMINUS_NUM tIMAGINARY %prec tLOWEST
|
||||||
|
{
|
||||||
|
/*%%%*/
|
||||||
|
$$ = negate_lit($2);
|
||||||
|
/*%
|
||||||
|
$$ = dispatch2(unary, ripper_intern("-@"), $2);
|
||||||
|
%*/
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
user_variable : tIDENTIFIER
|
user_variable : tIDENTIFIER
|
||||||
@ -5036,6 +5072,7 @@ static int parser_here_document(struct parser_params*,NODE*);
|
|||||||
# define heredoc_identifier() parser_heredoc_identifier(parser)
|
# define heredoc_identifier() parser_heredoc_identifier(parser)
|
||||||
# define heredoc_restore(n) parser_heredoc_restore(parser,(n))
|
# define heredoc_restore(n) parser_heredoc_restore(parser,(n))
|
||||||
# define whole_match_p(e,l,i) parser_whole_match_p(parser,(e),(l),(i))
|
# define whole_match_p(e,l,i) parser_whole_match_p(parser,(e),(l),(i))
|
||||||
|
# define number_literal_suffix(v, f) parser_number_literal_suffix(parser, (v), (f))
|
||||||
|
|
||||||
#ifndef RIPPER
|
#ifndef RIPPER
|
||||||
# define set_yylval_str(x) (yylval.node = NEW_STR(x))
|
# define set_yylval_str(x) (yylval.node = NEW_STR(x))
|
||||||
@ -6388,6 +6425,58 @@ parser_whole_match_p(struct parser_params *parser,
|
|||||||
return strncmp(eos, p, len) == 0;
|
return strncmp(eos, p, len) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define NUM_SUFFIX_R (1<<0)
|
||||||
|
#define NUM_SUFFIX_I (1<<1)
|
||||||
|
#define NUM_SUFFIX_ALL 3
|
||||||
|
|
||||||
|
static int
|
||||||
|
parser_number_literal_suffix(struct parser_params *parser, VALUE v, int const flag)
|
||||||
|
{
|
||||||
|
int c = nextc();
|
||||||
|
if ((flag & NUM_SUFFIX_R) > 0 && c == 'r') {
|
||||||
|
c = nextc();
|
||||||
|
if (c != 'i' && (ISALNUM(c) || c == '_')) {
|
||||||
|
pushback(c);
|
||||||
|
pushback('r');
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RB_TYPE_P(v, T_FLOAT)) {
|
||||||
|
v = rb_flt_rationalize(v);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
v = rb_rational_new(v, INT2FIX(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flag & NUM_SUFFIX_I) > 0 && c == 'i') {
|
||||||
|
c = nextc();
|
||||||
|
if (ISALNUM(c) || c == '_') {
|
||||||
|
pushback(c);
|
||||||
|
pushback('i');
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = rb_complex_new(INT2FIX(0), v);
|
||||||
|
}
|
||||||
|
pushback(c);
|
||||||
|
|
||||||
|
finish:
|
||||||
|
set_yylval_literal(v);
|
||||||
|
switch (TYPE(v)) {
|
||||||
|
case T_FIXNUM: case T_BIGNUM:
|
||||||
|
return tINTEGER;
|
||||||
|
case T_FLOAT:
|
||||||
|
return tFLOAT;
|
||||||
|
case T_RATIONAL:
|
||||||
|
return tRATIONAL;
|
||||||
|
case T_COMPLEX:
|
||||||
|
return tIMAGINARY;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
UNREACHABLE;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef RIPPER
|
#ifdef RIPPER
|
||||||
static void
|
static void
|
||||||
ripper_dispatch_heredoc_end(struct parser_params *parser)
|
ripper_dispatch_heredoc_end(struct parser_params *parser)
|
||||||
@ -7384,6 +7473,7 @@ parser_yylex(struct parser_params *parser)
|
|||||||
case '5': case '6': case '7': case '8': case '9':
|
case '5': case '6': case '7': case '8': case '9':
|
||||||
{
|
{
|
||||||
int is_float, seen_point, seen_e, nondigit;
|
int is_float, seen_point, seen_e, nondigit;
|
||||||
|
VALUE v;
|
||||||
|
|
||||||
is_float = seen_point = seen_e = nondigit = 0;
|
is_float = seen_point = seen_e = nondigit = 0;
|
||||||
lex_state = EXPR_END;
|
lex_state = EXPR_END;
|
||||||
@ -7417,8 +7507,8 @@ parser_yylex(struct parser_params *parser)
|
|||||||
no_digits();
|
no_digits();
|
||||||
}
|
}
|
||||||
else if (nondigit) goto trailing_uc;
|
else if (nondigit) goto trailing_uc;
|
||||||
set_yylval_literal(rb_cstr_to_inum(tok(), 16, FALSE));
|
v = rb_cstr_to_inum(tok(), 16, FALSE);
|
||||||
return tINTEGER;
|
return number_literal_suffix(v, NUM_SUFFIX_ALL);
|
||||||
}
|
}
|
||||||
if (c == 'b' || c == 'B') {
|
if (c == 'b' || c == 'B') {
|
||||||
/* binary */
|
/* binary */
|
||||||
@ -7441,8 +7531,8 @@ parser_yylex(struct parser_params *parser)
|
|||||||
no_digits();
|
no_digits();
|
||||||
}
|
}
|
||||||
else if (nondigit) goto trailing_uc;
|
else if (nondigit) goto trailing_uc;
|
||||||
set_yylval_literal(rb_cstr_to_inum(tok(), 2, FALSE));
|
v = rb_cstr_to_inum(tok(), 2, FALSE);
|
||||||
return tINTEGER;
|
return number_literal_suffix(v, NUM_SUFFIX_ALL);
|
||||||
}
|
}
|
||||||
if (c == 'd' || c == 'D') {
|
if (c == 'd' || c == 'D') {
|
||||||
/* decimal */
|
/* decimal */
|
||||||
@ -7465,8 +7555,8 @@ parser_yylex(struct parser_params *parser)
|
|||||||
no_digits();
|
no_digits();
|
||||||
}
|
}
|
||||||
else if (nondigit) goto trailing_uc;
|
else if (nondigit) goto trailing_uc;
|
||||||
set_yylval_literal(rb_cstr_to_inum(tok(), 10, FALSE));
|
v = rb_cstr_to_inum(tok(), 10, FALSE);
|
||||||
return tINTEGER;
|
return number_literal_suffix(v, NUM_SUFFIX_ALL);
|
||||||
}
|
}
|
||||||
if (c == '_') {
|
if (c == '_') {
|
||||||
/* 0_0 */
|
/* 0_0 */
|
||||||
@ -7497,8 +7587,8 @@ parser_yylex(struct parser_params *parser)
|
|||||||
pushback(c);
|
pushback(c);
|
||||||
tokfix();
|
tokfix();
|
||||||
if (nondigit) goto trailing_uc;
|
if (nondigit) goto trailing_uc;
|
||||||
set_yylval_literal(rb_cstr_to_inum(tok(), 8, FALSE));
|
v = rb_cstr_to_inum(tok(), 8, FALSE);
|
||||||
return tINTEGER;
|
return number_literal_suffix(v, NUM_SUFFIX_ALL);
|
||||||
}
|
}
|
||||||
if (nondigit) {
|
if (nondigit) {
|
||||||
pushback(c);
|
pushback(c);
|
||||||
@ -7514,8 +7604,7 @@ parser_yylex(struct parser_params *parser)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pushback(c);
|
pushback(c);
|
||||||
set_yylval_literal(INT2FIX(0));
|
return number_literal_suffix(INT2FIX(0), NUM_SUFFIX_ALL);
|
||||||
return tINTEGER;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7597,11 +7686,11 @@ parser_yylex(struct parser_params *parser)
|
|||||||
rb_warningS("Float %s out of range", tok());
|
rb_warningS("Float %s out of range", tok());
|
||||||
errno = 0;
|
errno = 0;
|
||||||
}
|
}
|
||||||
set_yylval_literal(DBL2NUM(d));
|
v = DBL2NUM(d);
|
||||||
return tFLOAT;
|
return number_literal_suffix(v, seen_e ? NUM_SUFFIX_I : NUM_SUFFIX_ALL);
|
||||||
}
|
}
|
||||||
set_yylval_literal(rb_cstr_to_inum(tok(), 10, FALSE));
|
v = rb_cstr_to_inum(tok(), 10, FALSE);
|
||||||
return tINTEGER;
|
return number_literal_suffix(v, NUM_SUFFIX_ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
case ')':
|
case ')':
|
||||||
|
78
rational.c
78
rational.c
@ -2004,39 +2004,28 @@ float_to_r(VALUE self)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
VALUE
|
||||||
* call-seq:
|
rb_flt_rationalize_with_prec(VALUE flt, VALUE prec)
|
||||||
* flt.rationalize([eps]) -> rational
|
|
||||||
*
|
|
||||||
* Returns a simpler approximation of the value (flt-|eps| <= result
|
|
||||||
* <= flt+|eps|). if the optional eps is not given, it will be chosen
|
|
||||||
* automatically.
|
|
||||||
*
|
|
||||||
* 0.3.rationalize #=> (3/10)
|
|
||||||
* 1.333.rationalize #=> (1333/1000)
|
|
||||||
* 1.333.rationalize(0.01) #=> (4/3)
|
|
||||||
*
|
|
||||||
* See to_r.
|
|
||||||
*/
|
|
||||||
static VALUE
|
|
||||||
float_rationalize(int argc, VALUE *argv, VALUE self)
|
|
||||||
{
|
{
|
||||||
VALUE e, a, b, p, q;
|
VALUE e, a, b, p, q;
|
||||||
|
|
||||||
if (f_negative_p(self))
|
e = f_abs(prec);
|
||||||
return f_negate(float_rationalize(argc, argv, f_abs(self)));
|
a = f_sub(flt, e);
|
||||||
|
b = f_add(flt, e);
|
||||||
|
|
||||||
rb_scan_args(argc, argv, "01", &e);
|
if (f_eqeq_p(a, b))
|
||||||
|
return f_to_r(flt);
|
||||||
|
|
||||||
if (argc != 0) {
|
nurat_rationalize_internal(a, b, &p, &q);
|
||||||
e = f_abs(e);
|
return rb_rational_new2(p, q);
|
||||||
a = f_sub(self, e);
|
}
|
||||||
b = f_add(self, e);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
VALUE f, n;
|
|
||||||
|
|
||||||
float_decode_internal(self, &f, &n);
|
VALUE
|
||||||
|
rb_flt_rationalize(VALUE flt)
|
||||||
|
{
|
||||||
|
VALUE a, b, f, n, p, q;
|
||||||
|
|
||||||
|
float_decode_internal(flt, &f, &n);
|
||||||
if (f_zero_p(f) || f_positive_p(n))
|
if (f_zero_p(f) || f_positive_p(n))
|
||||||
return rb_rational_new1(f_lshift(f, n));
|
return rb_rational_new1(f_lshift(f, n));
|
||||||
|
|
||||||
@ -2061,15 +2050,46 @@ float_rationalize(int argc, VALUE *argv, VALUE self)
|
|||||||
b = rb_rational_new2(f_add(radix_times_f, INT2FIX(FLT_RADIX - 1)), den);
|
b = rb_rational_new2(f_add(radix_times_f, INT2FIX(FLT_RADIX - 1)), den);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
if (f_eqeq_p(a, b))
|
if (f_eqeq_p(a, b))
|
||||||
return f_to_r(self);
|
return f_to_r(flt);
|
||||||
|
|
||||||
nurat_rationalize_internal(a, b, &p, &q);
|
nurat_rationalize_internal(a, b, &p, &q);
|
||||||
return rb_rational_new2(p, q);
|
return rb_rational_new2(p, q);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* flt.rationalize([eps]) -> rational
|
||||||
|
*
|
||||||
|
* Returns a simpler approximation of the value (flt-|eps| <= result
|
||||||
|
* <= flt+|eps|). if the optional eps is not given, it will be chosen
|
||||||
|
* automatically.
|
||||||
|
*
|
||||||
|
* 0.3.rationalize #=> (3/10)
|
||||||
|
* 1.333.rationalize #=> (1333/1000)
|
||||||
|
* 1.333.rationalize(0.01) #=> (4/3)
|
||||||
|
*
|
||||||
|
* See to_r.
|
||||||
|
*/
|
||||||
|
static VALUE
|
||||||
|
float_rationalize(int argc, VALUE *argv, VALUE self)
|
||||||
|
{
|
||||||
|
VALUE e;
|
||||||
|
|
||||||
|
if (f_negative_p(self))
|
||||||
|
return f_negate(float_rationalize(argc, argv, f_abs(self)));
|
||||||
|
|
||||||
|
rb_scan_args(argc, argv, "01", &e);
|
||||||
|
|
||||||
|
if (argc != 0) {
|
||||||
|
return rb_flt_rationalize_with_prec(self, e);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return rb_flt_rationalize(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
inline static int
|
inline static int
|
||||||
|
Loading…
x
Reference in New Issue
Block a user