/* 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;} } }