You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gnosygnu_xowa/100_core/src/gplx/Int_ary_.java

164 lines
5.6 KiB

/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx;
import gplx.core.strings.*;
public class Int_ary_ {//RF:DATE:2017-10-09
public static int[] Empty = new int[0];
public static int[] New(int... v) {return v;}
public static void Copy_to(int[] src, int src_len, int[] trg) {
for (int i = 0; i < src_len; ++i)
trg[i] = src[i];
}
public static String To_str(String spr, int... ary) {
Bry_bfr bfr = Bry_bfr_.New();
int len = ary.length;
for (int i = 0; i < len; ++i) {
if (i != 0) bfr.Add_str_u8(spr);
int itm = ary[i];
bfr.Add_int_variable(itm);
}
return bfr.To_str_and_clear();
}
public static int[] Parse(String raw, String spr) {
String[] ary = String_.Split(raw, spr);
int len = ary.length;
int[] rv = new int[len];
for (int i = 0; i < len; i++)
rv[i] = Int_.Parse(ary[i]);
return rv;
}
// parses to a reqd len; EX: "1" -> "[1, 0]"
public static int[] Parse(String raw_str, int reqd_len, int[] or) {
byte[] raw_bry = Bry_.new_a7(raw_str);
int raw_bry_len = raw_bry.length;
int[] rv = new int[reqd_len];
int cur_val = 0, cur_mult = 1, cur_idx = reqd_len - 1; boolean signed = false;
for (int i = raw_bry_len - 1; i > -2; i--) {
byte b = i == -1 ? Byte_ascii.Comma : raw_bry[i];
switch (b) {
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
if (signed) return or;
cur_val += (b - Byte_ascii.Num_0) * cur_mult;
cur_mult *= 10;
break;
case Byte_ascii.Space: case Byte_ascii.Nl: case Byte_ascii.Cr: case Byte_ascii.Tab:
break;
case Byte_ascii.Comma:
if (cur_idx < 0) return or;
rv[cur_idx--] = cur_val;
cur_val = 0; cur_mult = 1;
signed = false;
break;
case Byte_ascii.Dash:
if (signed) return or;
cur_val *= -1;
signed = true;
break;
case Byte_ascii.Plus: // noop; all values positive by default
if (signed) return or;
signed = true;
break;
default:
return or;
}
}
return cur_idx == -1 ? rv : or; // cur_idx == -1 checks for unfilled; EX: Ary_parse("1,2", 3, null) is unfilled
}
// optimizes parse
public static int[] Parse_or(byte[] src, int[] or) {
try {
if (Bry_.Len_eq_0(src)) return or; // null, "" should return [0]
int raw_len = src.length;
int[] rv = null; int rv_idx = 0, rv_len = 0;
int pos = 0;
int num_bgn = -1, num_end = -1;
boolean itm_done = false, itm_is_rng = false;
int rng_bgn = Int_.Min_value;
while (true) {
boolean pos_is_last = pos == raw_len;
if ( itm_done
|| pos_is_last
) {
if (num_bgn == -1) return or; // empty itm; EX: "1,"; "1,,2"
int num = Bry_.To_int_or(src, num_bgn, num_end, Int_.Min_value);
if (num == Int_.Min_value) return or; // not a number; parse failed
if (rv_len == 0) { // rv not init'd
rv_len = (raw_len / 2) + 1; // default rv_len to len of String / 2; + 1 to avoid fraction rounding down
rv = new int[rv_len];
}
int add_len = 1;
if (itm_is_rng) {
add_len = num - rng_bgn + List_adp_.Base1;
if (add_len == 0) return or; // bgn >= end;
}
if (add_len + rv_idx > rv_len) { // ary out of space; resize
rv_len = (add_len + rv_idx) * 2;
rv = (int[])Array_.Resize(rv, rv_len);
}
if (itm_is_rng) {
for (int i = rng_bgn; i <= num; i++)
rv[rv_idx++] = i;
}
else {
rv[rv_idx++] = num;
}
num_bgn = num_end = -1;
itm_done = itm_is_rng = false;
rng_bgn = Int_.Min_value;
if (pos_is_last) break;
}
byte b = src[pos];
switch (b) {
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
if (num_bgn == -1) // num_bgn not set
num_bgn = pos;
num_end = pos + 1; // num_end is always after pos; EX: "9": num_end = 1; "98,7": num_end=2
break;
case Byte_ascii.Space: case Byte_ascii.Tab: case Byte_ascii.Nl: case Byte_ascii.Cr: // NOTE: parseNumList replaces ws with '', so "1 1" will become "11"
break;
case Byte_ascii.Comma:
if (pos == raw_len -1) return or; // eos; EX: "1,"
if (num_bgn == -1) return or; // empty itm; EX: ","; "1,,2"
itm_done = true;
break;
case Byte_ascii.Dash:
if (pos == raw_len -1) return or; // eos; EX: "1-"
if (num_bgn == -1) return or; // no rng_bgn; EX: "-2"
rng_bgn = Bry_.To_int_or(src, num_bgn, pos, Int_.Min_value);
if (rng_bgn == Int_.Min_value) return or;
num_bgn = -1;
itm_is_rng = true;
break;
default:
return or;
}
++pos;
}
return (rv_idx == rv_len) // on the off-chance that rv_len == rv_idx; EX: "1"
? rv
: (int[])Array_.Resize(rv, rv_idx);
} catch (Exception e) {Err_.Noop(e); return or;}
}
}