1
0
mirror of https://github.com/gnosygnu/xowa.git synced 2026-03-02 03:49:30 +00:00

Refactor: Pull more classes into baselib

This commit is contained in:
gnosygnu
2021-12-19 16:19:19 -05:00
parent 48559edffe
commit 0e80d7ef6d
7999 changed files with 1375876 additions and 1365947 deletions

View File

@@ -13,7 +13,7 @@ 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.objects.events;
package gplx.frameworks.events;
import java.util.ArrayList;
import java.util.List;
public class GfoEvent<A> {

View File

@@ -13,7 +13,7 @@ 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.objects.events;
package gplx.frameworks.events;
public interface GfoEventOwner {
boolean EventsEnabled(); void EventsEnabledSet(boolean v);
}

View File

@@ -13,7 +13,7 @@ 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.objects.events;
package gplx.frameworks.events;
public interface GfoHandler<A> {
void Run(GfoEventOwner sender, A args);
}

View File

@@ -13,8 +13,7 @@ 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.objects.primitives;
public class FloatUtl {
public static final String ClsValName = "float";
public static final Class<?> ClsRefType = Float.class;
package gplx.frameworks.objects;
public interface ToStrAble {
String ToStr();
}

View File

@@ -13,10 +13,8 @@ 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.objects.errs;
import gplx.*; import gplx.objects.*;
public class Err extends RuntimeException {
private final String msg;
public Err(String msg) {this.msg = msg;}
@Override public String getMessage() {return msg;}
package gplx.frameworks.objects;
import gplx.types.basics.utls.ObjectUtl;
public class ToStrAbleUtl {
public static ToStrAble CastOrNull(Object obj) {return obj instanceof ToStrAble ? (ToStrAble)obj : null;}
}

View File

@@ -0,0 +1,270 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.frameworks.tests;
import gplx.frameworks.objects.ToStrAble;
import gplx.frameworks.objects.ToStrAbleUtl;
import gplx.types.basics.strings.bfrs.GfoStringBldr;
import gplx.types.basics.constants.CharCode;
import gplx.types.basics.utls.ArrayUtl;
import gplx.types.basics.utls.BoolUtl;
import gplx.types.basics.utls.BryLni;
import gplx.types.basics.utls.BryUtl;
import gplx.types.basics.utls.ByteUtl;
import gplx.types.basics.utls.CharUtl;
import gplx.types.basics.utls.ClassUtl;
import gplx.types.basics.utls.DoubleUtl;
import gplx.types.basics.utls.FloatUtl;
import gplx.types.basics.utls.IntUtl;
import gplx.types.basics.utls.LongUtl;
import gplx.types.basics.utls.ObjectUtl;
import gplx.types.basics.utls.StringUtl;
import gplx.types.basics.utls.TypeIds;
import gplx.types.commons.GfoDate;
import gplx.types.commons.GfoDecimal;
import gplx.types.errs.ErrUtl;
public class GfoTstr {
private static final GfoStringBldr bfr = new GfoStringBldr();
private static final String
EqN = "!= ",
Null = "<<NULL>>",
SectionBgn = "\n************************************************************************************************\n",
SectionMid = "\n------------------------------------------------------------------------------------------------\n",
SectionEnd = "________________________________________________________________________________________________";
public static void Debug(Object... ary) {Write(ary);}
public static void Write(byte[] s, int b, int e) {Write(BryLni.Mid(s, b, e));}
public static void Write() {Write("tmp");}
public static void Write(Object... ary) {
GfoStringBldr bfr = new GfoStringBldr();
int aryLen = ArrayUtl.Len(ary);
for (int i = 0; i < aryLen; i++) {
bfr.Add("'");
bfr.Add(ObjectUtl.ToStrOrNullMark(ary[i]));
bfr.Add("' ");
}
System.out.println(bfr.ToStr() + StringUtl.Nl);
}
public static void EqNull(Object actl) {EqNull(true , actl, null);}
public static void EqNull(Object actl, String fmt, Object... args) {EqNull(true , actl, StringUtl.Format(fmt, args));}
public static void EqNotNull(Object actl) {EqNull(false, actl, null);}
public static void EqNotNull(Object actl, String fmt, Object... args) {EqNull(false, actl, StringUtl.Format(fmt, args));}
private static final void EqNull(boolean expd, Object actl, String fmt, Object... args) {
if ( expd && actl != null
|| !expd && actl == null
) {
String expdStr = expd ? "null" : "not null";
String actlStr = actl == null ? "null" : "not null";
WriteAndThrow(expdStr, actlStr, fmt, args);
}
}
public static void EqBoolY(boolean actl) {Eq(true , actl, null);}
public static void EqBoolY(boolean actl, String fmt, Object... args) {Eq(true , actl, StringUtl.Format(fmt, args));}
public static void EqBoolN(boolean actl) {Eq(false, actl, null);}
public static void EqBoolN(boolean actl, String fmt, Object... args) {Eq(false, actl, StringUtl.Format(fmt, args));}
public static void Eq(boolean expd, boolean actl) {Eq(expd, actl, null);}
public static void Eq(boolean expd, boolean actl, String fmt, Object... args) {
if (expd != actl)
WriteAndThrow(BoolUtl.ToStrLower(expd), BoolUtl.ToStrLower(actl), fmt, args);
}
public static void EqByte(byte expd, byte actl) {Eq(expd, actl, null);}
public static void EqByte(byte expd, byte actl, String fmt, Object... args) {
if (expd != actl)
WriteAndThrow(ByteUtl.ToStr(expd), ByteUtl.ToStr(actl), fmt, args);
}
public static void Eq(int expd, int actl) {Eq(expd, actl, null);}
public static void Eq(int expd, int actl, String fmt, Object... args) {
if (expd != actl)
WriteAndThrow(IntUtl.ToStr(expd), IntUtl.ToStr(actl), fmt, args);
}
public static void EqLong(long expd, long actl) {EqLong(expd, actl, null);}
public static void EqLong(long expd, long actl, String fmt, Object... args) {
if (expd != actl)
WriteAndThrow(LongUtl.ToStr(expd), LongUtl.ToStr(actl), fmt, args);
}
public static void EqFloat(float expd, float actl) {EqFloat(expd, actl, null);}
public static void EqFloat(float expd, float actl, String fmt, Object... args) {
if (expd != actl)
WriteAndThrow(FloatUtl.ToStr(expd), FloatUtl.ToStr(actl), fmt, args);
}
public static void EqDouble(double expd, double actl) {EqDouble(expd, actl, null);}
public static void EqDouble(double expd, double actl, String fmt, Object... args) {
if (expd != actl)
WriteAndThrow(DoubleUtl.ToStr(expd), DoubleUtl.ToStr(actl), fmt, args);
}
public static void Eq(byte[] expd, byte[] actl) {Eq(StringUtl.NewU8(expd), StringUtl.NewU8(actl), null);}
public static void Eq(byte[] expd, byte[] actl, String fmt, Object... args) {Eq(StringUtl.NewU8(expd), StringUtl.NewU8(actl), fmt, args);}
public static void Eq(byte[] expd, String actl) {Eq(StringUtl.NewU8(expd), actl, null);}
public static void Eq(byte[] expd, String actl, String fmt, Object... args) {Eq(StringUtl.NewU8(expd), actl, fmt, args);}
public static void Eq(String expd, byte[] actl) {Eq(expd, StringUtl.NewU8(actl), null);}
public static void Eq(String expd, byte[] actl, String fmt, Object... args) {Eq(expd, StringUtl.NewU8(actl), fmt, args);}
public static void Eq(String expd, String actl) {Eq(expd, actl, null);}
public static void Eq(String expd, String actl, String fmt, Object... args) {
if (!StringUtl.Eq(expd, actl))
WriteAndThrow(expd, actl, fmt, args);
}
public static void Eq(GfoDate expd, GfoDate actl) {Eq(expd.ToStrGplx(), actl.ToStrGplx());}
public static void Eq(GfoDate expd, GfoDate actl, String fmt, Object... args) {Eq(expd.ToStrGplx(), actl.ToStrGplx(), fmt, args);}
public static void Eq(GfoDecimal expd, GfoDecimal actl) {EqDouble(expd.ToDouble(), actl.ToDouble());}
public static void EqErr(Exception exc, Class<?> type) {
if (!ClassUtl.Eq(exc.getClass(), type))
throw ErrUtl.NewArgs("error types do not match", "expdType", ClassUtl.CanonicalName(type), "actlType", ClassUtl.NameByObj(exc), "actlMsg", ErrUtl.Message(exc));
}
public static void ErrHas(Exception e, String hdr) {
if (!StringUtl.Has(ErrUtl.ToStrFull(e), hdr))
throw ErrUtl.NewFmt("could not find '{0}' in '{1}'", hdr, ErrUtl.ToStrFull(e));
}
public static void Eq(ToStrAble expd, ToStrAble actl) {Eq(expd.ToStr(), actl.ToStr());}
public static void Eq(ToStrAble expd, ToStrAble actl, String fmt, Object... args) {Eq(expd.ToStr(), actl.ToStr(), fmt, args);}
public static void EqObj(Object expd, Object actl) {EqObj(expd, actl, "");}
public static void EqObj(Object expd, Object actl, String msgFmt, Object... msgArgs) {
if (!ObjectUtl.Eq(expd, actl))
WriteAndThrow(ObjectUtl.ToStr(expd), ObjectUtl.ToStr(actl), msgFmt, msgArgs);
}
public static void EqObjToStr(Object expd, Object actl) {
Eq(ObjectUtl.ToStrOrNullMark(expd), ObjectUtl.ToStrOrNullMark(actl));
}
// NOTE: EqLines will ignore differences in last trailing line; EX: expd="a" == actl ="a\n"
public static void EqLines(String expd, String actl) {EqAry(TypeIds.IdStr, SplitLines(expd), SplitLines(actl), null);}
public static void EqLines(String expd, String actl, String fmt, Object... args) {EqAry(TypeIds.IdStr, SplitLines(expd), SplitLines(actl), fmt, args);}
public static void EqLines(String expd, byte[] actl) {EqAry(TypeIds.IdStr, SplitLines(expd), SplitLines(StringUtl.NewU8(actl)), null);}
public static void EqLines(String expd, byte[] actl, String fmt, Object... args) {EqAry(TypeIds.IdStr, SplitLines(expd), SplitLines(StringUtl.NewU8(actl)), fmt, args);}
public static void EqLines(byte[][] expd, byte[][] actl) {EqAry(TypeIds.IdBry, expd, actl, null);}
public static void EqLines(byte[][] expd, byte[][] actl, String fmt, Object... args) {EqAry(TypeIds.IdBry, expd, actl, fmt, args);}
public static void EqLines(String[] expd, String[] actl) {EqAry(TypeIds.IdBry, BryUtl.Ary(expd), BryUtl.Ary(actl), null);}
public static void EqLines(String[] expd, String[] actl, String fmt, Object... args) {EqAry(TypeIds.IdBry, BryUtl.Ary(expd), BryUtl.Ary(actl), fmt, args);}
public static void EqLines(String[] expd, byte[][] actl) {EqAry(TypeIds.IdBry, BryUtl.Ary(expd), actl, null);}
public static void EqLines(String[] expd, byte[][] actl, String fmt, Object... args) {EqAry(TypeIds.IdBry, BryUtl.Ary(expd), actl, fmt, args);}
public static void EqAry(boolean[] expd, boolean[] actl) {EqAry(TypeIds.IdBool, expd, actl, null);}
public static void EqAry(boolean[] expd, boolean[] actl, String fmt, Object... args) {EqAry(TypeIds.IdBool, expd, actl, fmt, args);}
public static void EqAry(byte[] expd, byte[] actl) {EqAry(TypeIds.IdByte, expd, actl, null);}
public static void EqAry(byte[] expd, byte[] actl, String fmt, Object... args) {EqAry(TypeIds.IdByte, expd, actl, fmt, args);}
public static void EqAry(int[] expd, int[] actl) {EqAry(TypeIds.IdInt, expd, actl, null);}
public static void EqAry(int[] expd, int[] actl, String msg) {EqAry(TypeIds.IdInt, expd, actl, msg);}
public static void EqAry(long[] expd, long[] actl) {EqAry(TypeIds.IdLong, expd, actl, null);}
public static void EqAry(long[] expd, long[] actl, String msg) {EqAry(TypeIds.IdLong, expd, actl, msg);}
public static void EqAry(int[] expd, int[] actl, String msg, Object... args) {EqAry(TypeIds.IdInt, expd, actl, msg, args);}
public static void EqAryObj(Object expd, Object actl) {EqAry(TypeIds.IdObj, expd, actl, null);}
public static void EqAryObj(Object expd, Object actl, String fmt, Object... args) {EqAry(TypeIds.IdObj, expd, actl, fmt, args);}
private static String[] SplitLines(String s) {
if (s == null) s = "";
return StringUtl.Split(s, CharUtl.NewLine);
}
// NOTE: EqAryObjAry compares on .toString, not .equals; this should be changed to compare on .equals, but need to add .equals to .hashcode to multiple types
private static final int IdToStr = -1;
public static void EqAryObjAry(Object[] expd, Object[] actl) {EqAry(IdToStr, expd, actl, null);}
public static void EqAryObjAry(Object[] expd, Object[] actl, String fmt, Object... args) {EqAry(IdToStr, expd, actl, fmt, args);}
private static final void EqAry(int typeTid, Object expdAry, Object actlAry, String msgFmt, Object... msgArgs) {
boolean[] failures = CalcFailures(typeTid, expdAry, actlAry);
if (failures != null) {
WriteFailHead(bfr, msgFmt, msgArgs);
WriteFailBody(bfr, failures, typeTid, expdAry, actlAry);
throw ErrUtl.NewMsg(bfr.ToStrAndClear());
}
}
public static void Fail(String fmt, Object... args) {
throw ErrUtl.NewMsg(StringUtl.Format(fmt, args));
}
public static void FailBcExpdError() {Eq(false, true, "fail expd error");}
private static boolean[] CalcFailures(int tid, Object expdAry, Object actlAry) {
int expdLen = ArrayUtl.Len(expdAry);
int actlLen = ArrayUtl.Len(actlAry);
int maxLen = expdLen > actlLen ? expdLen : actlLen;
if (maxLen == 0) return null; // exit early if both arys are empty
boolean[] rv = null;
for (int i = 0; i < maxLen; i++) {
Object expdObj = i < expdLen ? ArrayUtl.GetAt(expdAry, i) : null;
Object actlObj = i < actlLen ? ArrayUtl.GetAt(actlAry, i) : null;
boolean eq = false;
if (expdObj == null && actlObj == null) eq = true;
else if (expdObj == null || actlObj == null) eq = false;
else {
switch (tid) {
case TypeIds.IdBool: eq = BoolUtl.Cast(expdObj) == BoolUtl.Cast(actlObj); break;
case TypeIds.IdLong: eq = LongUtl.Cast(expdObj) == LongUtl.Cast(actlObj); break;
case TypeIds.IdInt: eq = IntUtl.Cast(expdObj) == IntUtl.Cast(actlObj); break;
case TypeIds.IdByte: eq = ByteUtl.Cast(expdObj) == ByteUtl.Cast(actlObj); break;
case TypeIds.IdBry: eq = BryLni.Eq((byte[])expdObj, (byte[])actlObj); break;
case TypeIds.IdObj: eq = ObjectUtl.Eq(expdObj, actlObj); break;
case TypeIds.IdStr: eq = StringUtl.Eq(StringUtl.Cast(expdObj), StringUtl.Cast(actlObj)); break;
case IdToStr: eq = StringUtl.Eq(ToStrOrNativeToString(expdObj), ToStrOrNativeToString(actlObj)); break;
}
}
if (!eq) {
if (rv == null) {
rv = new boolean[maxLen];
}
rv[i] = true;
}
}
return rv;
}
private static void WriteFailHead(GfoStringBldr bfr, String msgFmt, Object[] msgArgs) {
bfr.Add(SectionBgn);
if (msgFmt != null) {
bfr.Add(StringUtl.Format(msgFmt, msgArgs));
bfr.Add(SectionMid);
}
}
private static void WriteFailBody(GfoStringBldr bfr, boolean[] failures, int typeId, Object expdAry, Object actlAry) {
int len = failures.length;
int expdLen = ArrayUtl.Len(expdAry);
int actlLen = ArrayUtl.Len(actlAry);
for (int i = 0; i < len; i++) {
boolean failure = failures[i];
int padLen = 5 - IntUtl.CountDigits(i); // 5=assuming no more than 9999 failures in one test
bfr.AddIntPadBgn(CharCode.Num0, padLen, i).AddCharColon().AddCharSpace();
WriteFailItm(bfr, typeId, expdAry, expdLen, i);
if (failure) {
bfr.Add(EqN).AddCharRepeat(CharCode.Space, padLen - 1);
WriteFailItm(bfr, typeId, actlAry, actlLen, i);
}
}
bfr.Add(SectionEnd);
}
private static void WriteFailItm(GfoStringBldr bfr, int typeId, Object ary, int len, int idx) {
if (idx < len) {
Object val = ArrayUtl.GetAt(ary, idx);
switch (typeId) {
case TypeIds.IdBool: bfr.AddBoolAsYn(BoolUtl.Cast(val)); break;
case TypeIds.IdBry: bfr.Add((byte[])val); break;
case TypeIds.IdLong: bfr.AddLong(LongUtl.Cast(val)); break;
case TypeIds.IdInt: bfr.Add(IntUtl.Cast(val)); break;
case TypeIds.IdByte: bfr.Add(ByteUtl.Cast(val)); break;
case TypeIds.IdObj: bfr.Add(ObjectUtl.ToStr(val)); break;
case TypeIds.IdStr: bfr.Add(StringUtl.Cast(val)); break;
case IdToStr: bfr.Add(ToStrOrNativeToString(val)); break;
default: throw ErrUtl.NewUnhandled(typeId);
}
}
else
bfr.Add(Null);
bfr.AddCharNl();
}
protected static void WriteAndThrow(String expd, String actl, String msgFmt, Object... msgArgs) {
WriteFailHead(bfr, msgFmt, msgArgs);
bfr.Add("expd: ").Add(expd).AddCharNl();
bfr.Add("actl: ").Add(actl).AddCharNl();
bfr.Add(SectionEnd);
throw ErrUtl.NewMsg(bfr.ToStrAndClear());
}
private static String ToStrOrNativeToString(Object o) {
ToStrAble strAble = ToStrAbleUtl.CastOrNull(o);
return strAble == null
? ObjectUtl.ToStrOrNullMark(o)
: strAble.ToStr();
}
}

View File

@@ -0,0 +1,34 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.langs.html;
import gplx.types.basics.utls.BryUtl;
public class HtmlEntityCodes {
public static final String
NlStr = "&#10;"
;
public static final byte[]
LtBry = BryUtl.NewA7("&lt;"),
GtBry = BryUtl.NewA7("&gt;"),
AmpBry = BryUtl.NewA7("&amp;"),
QuoteBry = BryUtl.NewA7("&quot;"),
AposNumBry = BryUtl.NewA7("&#39;"),
EqBry = BryUtl.NewA7("&#61;"),
NlBry = BryUtl.NewA7(NlStr),
CrBry = BryUtl.NewA7("&#13;"),
TabBry = BryUtl.NewA7("&#9;"),
SpaceBry = BryUtl.NewA7("&#32;"),
NbspNumBry = BryUtl.NewA7("&#160;");
}

View File

@@ -0,0 +1,9 @@
package gplx.libs.ios;
public class IoConsts {
public static final int
LenKB = 1024,
LenMB = 1048576,
LenGB = 1073741824;
public static final long LenMBAsLong = LenMB;
public static final long LenNull = -1;
}

View File

@@ -1,34 +0,0 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.objects;
import gplx.objects.arrays.BryUtl;
import gplx.objects.strings.StringUtl;
import gplx.objects.types.TypeUtl;
public class ObjectUtl {
public static String ToStrOrNullMark(Object v) {return v == null ? "<<NULL>>": ToStr(v);}
public static String ToStrOr(Object v, String or) {return v == null ? or : ToStr(v);}
public static String ToStr(Object v) {
Class<?> c = v.getClass();
if (TypeUtl.Eq(c, StringUtl.ClsRefType)) return (String)v;
else if (TypeUtl.Eq(c, BryUtl.ClsRefType)) return StringUtl.NewByBryUtf8((byte[])v);
else return v.toString();
}
public static boolean Eq(Object lhs, Object rhs) {
if (lhs == null && rhs == null) return true;
else if (lhs == null || rhs == null) return false;
else return lhs.equals(rhs);
}
}

View File

@@ -1,115 +0,0 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.objects.arrays;
import gplx.objects.errs.ErrUtl;
public class BryUtl {
public static final Class<?> ClsRefType = byte[].class;
public static final byte[] Empty = new byte[0];
public static boolean Eq(byte[] lhs, byte[] rhs) {return Eq(lhs, 0, lhs == null ? 0 : lhs.length, rhs);}
public static boolean Eq(byte[] lhs, int lhsBgn, int lhsEnd, byte[] rhs) {
if (lhs == null && rhs == null) return true;
else if (lhs == null || rhs == null) return false;
if (lhsBgn < 0) return false;
int rhsLen = rhs.length;
if (rhsLen != lhsEnd - lhsBgn) return false;
int lhsLen = lhs.length;
for (int i = 0; i < rhsLen; i++) {
int lhsPos = i + lhsBgn;
if (lhsPos == lhsLen) return false;
if (rhs[i] != lhs[lhsPos]) return false;
}
return true;
}
public static byte[][] Ary(byte[]... ary) {return ary;}
public static byte[][] Ary(String... ary) {
int aryLen = ary.length;
byte[][] rv = new byte[aryLen][];
for (int i = 0; i < aryLen; i++) {
String itm = ary[i];
rv[i] = itm == null ? null : BryUtl.NewUtf08(itm);
}
return rv;
}
public static byte[] NewA7(String str) {
if (str == null) return null;
int str_len = str.length();
if (str_len == 0) return Empty;
byte[] rv = new byte[str_len];
for (int i = 0; i < str_len; ++i) {
char c = str.charAt(i);
if (c > 128) c = '?';
rv[i] = (byte)c;
}
return rv;
}
public static byte[] NewUtf08(String src) {
try {
int srcLen = src.length();
if (srcLen == 0) return BryUtl.Empty;
int bryLen = NewUtf08Count(src, srcLen);
byte[] bry = new byte[bryLen];
NewUtf08Write(src, srcLen, bry, 0);
return bry;
}
catch (Exception e) {throw ErrUtl.NewFmt(e, "invalid UTF-8 sequence; src={0}", src);}
}
private static int NewUtf08Count(String src, int srcLen) {
int rv = 0;
for (int i = 0; i < srcLen; ++i) {
char c = src.charAt(i);
int cLen = 0;
if ( c < 128) cLen = 1; // 1 << 7
else if ( c < 2048) cLen = 2; // 1 << 11
else if ( (c > 55295) // 0xD800
&& (c < 56320)) cLen = 4; // 0xDFFF
else cLen = 3; // 1 << 16
if (cLen == 4) ++i; // surrogate is 2 wide, not 1
rv += cLen;
}
return rv;
}
private static void NewUtf08Write(String src, int srcLen, byte[] bry, int bryPos) {
for (int i = 0; i < srcLen; ++i) {
char c = src.charAt(i);
if ( c < 128) {
bry[bryPos++] = (byte)c;
}
else if ( c < 2048) {
bry[bryPos++] = (byte)(0xC0 | (c >> 6));
bry[bryPos++] = (byte)(0x80 | (c & 0x3F));
}
else if ( (c > 55295) // 0xD800
&& (c < 56320)) { // 0xDFFF
if (i >= srcLen) throw ErrUtl.NewMsg("incomplete surrogate pair at end of String");
char nxtChar = src.charAt(i + 1);
int v = 0x10000 + (c - 0xD800) * 0x400 + (nxtChar - 0xDC00);
bry[bryPos++] = (byte)(0xF0 | (v >> 18));
bry[bryPos++] = (byte)(0x80 | (v >> 12) & 0x3F);
bry[bryPos++] = (byte)(0x80 | (v >> 6) & 0x3F);
bry[bryPos++] = (byte)(0x80 | (v & 0x3F));
++i;
}
else {
bry[bryPos++] = (byte)(0xE0 | (c >> 12));
bry[bryPos++] = (byte)(0x80 | (c >> 6) & 0x3F);
bry[bryPos++] = (byte)(0x80 | (c & 0x3F));
}
}
}
}

View File

@@ -1,43 +0,0 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.objects.errs;
import gplx.objects.ObjectUtl;
import gplx.objects.strings.StringUtl;
public class ErrUtl {
public static void Noop(Exception e) {}
public static Err NewMsg(String msg) {return new Err(msg);}
public static Err NewFmt(String fmt, Object... args) {return new Err(StringUtl.Format(fmt, args));}
public static Err NewFmt(Exception e, String fmt, Object... args) {return new Err(StringUtl.Format(fmt, args) + " exc=" + ErrUtl.MessageLang(e));}
public static Err NewNull(String name) {return new Err("object was null; name=" + name);}
public static Err NewUnhandledDefault(Object o) {return new Err("val is not in switch; val=" + ObjectUtl.ToStr(o));}
public static Err NewUnimplemented() {return new Err("method is not implemented");}
public static Err NewParse(Class<?> cls, String raw) {return new Err("parse failed; cls=" + cls.getCanonicalName() + "; raw=" + raw);}
public static String MessageLang(Exception e) {
return Error.class.isAssignableFrom(e.getClass())
? e.toString() // java.lang.Error returns null for "getMessage()"; return "toString()" instead
: e.getMessage();
}
public static String TraceLang(Throwable e) {
StackTraceElement[] ary = e.getStackTrace();
String rv = "";
for (int i = 0; i < ary.length; i++) {
if (i != 0) rv += "\n";
rv += ary[i].toString();
}
return rv;
}
}

View File

@@ -1,110 +0,0 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.objects.primitives;
import gplx.objects.ObjectUtl;
import gplx.objects.errs.ErrUtl;
import gplx.objects.strings.StringUtl;
public class IntUtl {
public static final String ClsValName = "int";
public static final Class<?> ClsRefType = Integer.class;
public static final int
MinValue = Integer.MIN_VALUE,
MaxValue = Integer.MAX_VALUE,
MaxValue31 = 2147483647,
Neg1 = -1,
Null = IntUtl.MinValue,
Base1 = 1, // for base-1 lists / arrays; EX: PHP; [a, b, c]; [1] => a
Offset1 = 1; // common symbol for + 1 after current pos; EX: StringUtl.Mid(lhs + Offset1, rhs)
public static int Cast(Object o) {
try {
return (Integer)o;
}
catch(Exception e) {
throw ErrUtl.NewFmt(e, "failed to cast to int; obj={0}", ObjectUtl.ToStr(o));
}
}
public static String ToStr(int v) {return new Integer(v).toString();}
public static int ParseOr(String raw, int or) {
// process args
if (raw == null) return or;
int rawLen = StringUtl.Len(raw);
if (rawLen == 0) return or;
// loop backwards from nth to 0th char
int rv = 0, powerOf10 = 1;
for (int idx = rawLen - 1; idx >= 0; idx--) {
char cur = StringUtl.CharAt(raw, idx);
int digit = -1;
switch (cur) {
// numbers -> assign digit
case '0': digit = 0; break; case '1': digit = 1; break; case '2': digit = 2; break; case '3': digit = 3; break; case '4': digit = 4; break;
case '5': digit = 5; break; case '6': digit = 6; break; case '7': digit = 7; break; case '8': digit = 8; break; case '9': digit = 9; break;
// negative sign
case '-':
if (idx != 0) { // invalid if not 1st
return or;
}
else { // is first; multiply by -1
rv *= -1;
continue;
}
// anything else
default:
return or;
}
rv += (digit * powerOf10);
powerOf10 *= 10;
}
return rv;
}
public static boolean Between(int v, int lhs, int rhs) {
int lhsComp = v == lhs ? 0 : (v < lhs ? -1 : 1);
int rhsComp = v == rhs ? 0 : (v < rhs ? -1 : 1);
return (lhsComp * rhsComp) != 1; // 1 when v is (a) greater than both or (b) less than both
}
private static int[] Log10Vals = new int[] {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, IntUtl.MaxValue};
public static int Log10(int v) {
if (v == 0) return 0;
int sign = 1;
if (v < 0) {
if (v == IntUtl.MinValue) return -9; // NOTE: IntUtl.MinValue * -1 = IntUtl.MinValue
v *= -1;
sign = -1;
}
int log10sLen = Log10Vals.length;
int rv = log10sLen - 2; // rv will only happen when v == IntUtl.MaxValue
int bgn = 0;
if (v > 1000) { // optimization to reduce number of ops to < 5
bgn = 3;
if (v > 1000000) bgn = 6;
}
for (int i = bgn; i < log10sLen; i++) {
if (v < Log10Vals[i]) {rv = i - 1; break;}
}
return rv * sign;
}
public static int CountDigits(int v) {
int log10 = Log10(v);
return v > -1 ? log10 + 1 : log10 * -1 + 2;
}
}

View File

@@ -1,96 +0,0 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.objects.strings;
import gplx.objects.ObjectUtl;
import gplx.objects.arrays.ArrayUtl;
import gplx.objects.errs.ErrUtl;
import gplx.objects.primitives.IntUtl;
import gplx.objects.strings.bfrs.GfoStrBldr;
public class StringUtl {
public static final Class<?> ClsRefType = String.class;
public static final String ClsValName = "str" + "ing";
public static final int FindNone = -1, PosNeg1 = -1;
public static final String Empty = "", NullMark = "<<NULL>>", Tab = "\t", Lf = "\n", CrLf = "\r\n";
public static boolean Eq(String lhs, String rhs) {return lhs == null ? rhs == null : lhs.equals(rhs);}
public static int Len(String s) {return s.length();}
public static char CharAt(String s, int i) {return s.charAt(i);}
// use C# flavor ("a {0}") rather than Java format ("a %s"); also: (a) don't fail on format errors; (b) escape brackets by doubling
private static final char FormatItmLhs = '{', FormatItmRhs = '}';
public static String Format(String fmt, Object... args) {
// method vars
int argsLen = ArrayUtl.LenObjAry(args);
if (argsLen == 0) return fmt; // nothing to format
int fmtLen = Len(fmt);
// loop vars
int pos = 0; String argIdxStr = ""; boolean insideBrackets = false;
GfoStrBldr bfr = new GfoStrBldr();
while (pos < fmtLen) { // loop over every char; NOTE: UT8-SAFE b/c only checking for "{"; "}"
char c = CharAt(fmt, pos);
if (insideBrackets) {
if (c == FormatItmLhs) { // first FormatItmLhs is fake; add FormatItmLhs and whatever is in argIdxStr
bfr.AddChar(FormatItmLhs).Add(argIdxStr);
argIdxStr = "";
}
else if (c == FormatItmRhs) { // itm completed
int argsIdx = IntUtl.ParseOr(argIdxStr, IntUtl.MinValue);
String itm = argsIdx != IntUtl.MinValue && IntUtl.Between(argsIdx, 0, argsLen - 1) // check (a) argsIdx is num; (b) argsIdx is in bounds
? ObjectUtl.ToStrOrNullMark(args[argsIdx]) // valid; add itm
: FormatItmLhs + argIdxStr + FormatItmRhs; // not valid; just add String
bfr.Add(itm);
insideBrackets = false;
argIdxStr = "";
}
else
argIdxStr += c;
}
else {
if (c == FormatItmLhs || c == FormatItmRhs) {
boolean posIsEnd = pos == fmtLen - 1;
if (posIsEnd) // last char is "{" or "}" (and not insideBrackets); ignore and just ad
bfr.AddChar(c);
else {
char next = CharAt(fmt, pos + 1);
if (next == c) { // "{{" or "}}": escape by doubling
bfr.AddChar(c);
pos++;
}
else
insideBrackets = true;
}
}
else
bfr.AddChar(c);
}
pos++;
}
if (Len(argIdxStr) > 0) // unclosed bracket; add FormatItmLhs and whatever is in argIdxStr; ex: "{0"
bfr.AddChar(FormatItmLhs).Add(argIdxStr);
return bfr.ToStr();
}
public static String NewByBryUtf8(byte[] v) {return v == null ? null : NewByBryUtf8(v, 0, v.length);}
public static String NewByBryUtf8(byte[] v, int bgn, int end) {
try {
return v == null
? null
: new String(v, bgn, end - bgn, "UTF-8");
}
catch (Exception e) {throw ErrUtl.NewFmt(e, "unsupported encoding; bgn={0} end={1}", bgn, end);}
}
}

View File

@@ -1,88 +0,0 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.objects.strings.bfrs;
import gplx.objects.primitives.BoolUtl;
import gplx.objects.primitives.CharCode;
import gplx.objects.primitives.IntUtl;
import gplx.objects.strings.StringUtl;
import gplx.objects.strings.unicodes.UstringUtl;
public class GfoStrBldr {
private StringBuilder sb = new StringBuilder();
public int Len() {return sb.length();}
public boolean HasNone() {return this.Len() == 0;}
public boolean HasSome() {return this.Len() > 0;}
public GfoStrBldr Clear() {Del(0, this.Len()); return this;}
public GfoStrBldr Del(int bgn, int len) {sb.delete(bgn, len); return this;}
public GfoStrBldr AddFmt(String format, Object... args) {Add(StringUtl.Format(format, args)); return this;}
public GfoStrBldr AddAt(int idx, String s) {sb.insert(idx, s); return this;}
public GfoStrBldr Add(String s) {sb.append(s); return this;}
public GfoStrBldr AddChar(char c) {sb.append(c); return this;}
public GfoStrBldr AddByte(byte i) {sb.append(i); return this;}
public GfoStrBldr AddInt(int i) {sb.append(i); return this;}
public GfoStrBldr AddLong(long i) {sb.append(i); return this;}
public GfoStrBldr AddDouble(double i) {sb.append(i); return this;}
public GfoStrBldr AddObj(Object o) {sb.append(o); return this;}
public GfoStrBldr AddBry(byte[] v) {
if (v != null)
sb.append(StringUtl.NewByBryUtf8(v));
return this;
}
public GfoStrBldr AddMid(String s, int bgn) {sb.append(s, bgn, s.length()); return this;}
public GfoStrBldr AddMid(String s, int bgn, int count) {sb.append(s, bgn, count); return this;}
public GfoStrBldr AddBool(boolean val) {
this.Add(val ? BoolUtl.TrueStr : BoolUtl.FalseStr);
return this;
}
public GfoStrBldr AddBoolAsYn(boolean val) {
this.Add(val ? "y" : "n");
return this;
}
public GfoStrBldr AddCharNl() {return AddChar(CharCode.NewLine);}
public GfoStrBldr AddCharSpace() {return AddChar(CharCode.Space);}
public GfoStrBldr AddCharColon() {return AddChar(CharCode.Colon);}
public GfoStrBldr AddCharRepeat(char c, int repeat) {
this.EnsureCapacity(this.Len() + repeat);
for (int i = 0; i < repeat; i++)
AddChar(c);
return this;
}
public GfoStrBldr AddCharByCode(int code) {
if (code >= UstringUtl.SurrogateCpBgn && code <= UstringUtl.SurrogateCpEnd) {
sb.append((char)((code - 0x10000) / 0x400 + 0xD800));
sb.append((char)((code - 0x10000) % 0x400 + 0xDC00));
}
else {
sb.append((char)code);
}
return this;
}
public GfoStrBldr AddIntPadBgn(char padChar, int strLen, int val) {
int digitLen = IntUtl.CountDigits(val);
int padLen = strLen - digitLen;
if (padLen > 0) // note that this skips padLen == 0, as well as guarding against negative padLen; EX: pad(" ", 3, 1234) -> "1234"
AddCharRepeat(padChar, padLen);
AddInt(val);
return this;
}
public String ToStr() {return sb.toString();}
public String ToStrAndClear() {
String rv = ToStr();
Clear();
return rv;
}
@Override public String toString() {return ToStr();}
private void EnsureCapacity(int capacity) {sb.ensureCapacity(capacity);}
}

View File

@@ -1,171 +0,0 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.tests;
import gplx.objects.ObjectUtl;
import gplx.objects.arrays.ArrayUtl;
import gplx.objects.arrays.BryUtl;
import gplx.objects.errs.ErrUtl;
import gplx.objects.primitives.BoolUtl;
import gplx.objects.primitives.ByteUtl;
import gplx.objects.primitives.CharCode;
import gplx.objects.primitives.IntUtl;
import gplx.objects.primitives.LongUtl;
import gplx.objects.strings.StringUtl;
import gplx.objects.strings.bfrs.GfoStrBldr;
import gplx.objects.types.TypeIds;
public class GfoTstr {
private static final GfoStrBldr bfr = new GfoStrBldr();
private static final String
EqN = "!= ",
Null = "<<NULL>>",
SectionBgn = "\n************************************************************************************************\n",
SectionMid = "\n------------------------------------------------------------------------------------------------\n",
SectionEnd = "________________________________________________________________________________________________";
public static void Write(Object... ary) {
GfoStrBldr bfr = new GfoStrBldr();
int aryLen = ArrayUtl.Len(ary);
for (int i = 0; i < aryLen; i++) {
bfr.Add("'");
bfr.Add(ObjectUtl.ToStrOrNullMark(ary[i]));
bfr.Add("' ");
}
System.out.println(bfr.ToStr() + StringUtl.Lf);
}
public static void EqNull(boolean expd, Object val) {EqNull(expd, val, null);}
public static void EqNull(boolean expd, Object val, String msgFmt, Object... msgArgs) {
if ( expd && val != null
|| !expd && val == null
) {
String expdStr = expd ? "null" : "not null";
String actlStr = val == null ? "null" : "not null";
WriteAndThrow(expdStr, actlStr, msgFmt, msgArgs);
}
}
public static void EqBoolY(boolean actl) {EqBool(BoolUtl.Y, actl, null);}
public static void EqBool(boolean expd, boolean actl) {EqBool(expd, actl, null);}
public static void EqBool(boolean expd, boolean actl, String msgFmt, Object... msgArgs) {
if (expd != actl)
WriteAndThrow(BoolUtl.ToStrLower(expd), BoolUtl.ToStrLower(actl), msgFmt, msgArgs);
}
public static void EqInt(int expd, int actl) {EqInt(expd, actl, null);}
public static void EqInt(int expd, int actl, String msgFmt, Object... msgArgs) {
if (expd != actl)
WriteAndThrow(IntUtl.ToStr(expd), IntUtl.ToStr(actl), msgFmt, msgArgs);
}
public static void EqLong(long expd, long actl) {EqLong(expd, actl, null);}
public static void EqLong(long expd, long actl, String msgFmt, Object... msgArgs) {
if (expd != actl)
WriteAndThrow(LongUtl.ToStr(expd), LongUtl.ToStr(actl), msgFmt, msgArgs);
}
public static void EqStr(String expd, byte[] actl, String msgFmt, Object... msgArgs) {EqStr(expd, StringUtl.NewByBryUtf8(actl), msgFmt, msgArgs);}
public static void EqStr(String expd, byte[] actl) {EqStr(expd, StringUtl.NewByBryUtf8(actl), null);}
public static void EqStr(String expd, String actl) {EqStr(expd, actl, null);}
public static void EqStr(String expd, String actl, String msgFmt, Object... msgArgs) {
if (!StringUtl.Eq(expd, actl))
WriteAndThrow(expd, actl, msgFmt, msgArgs);
}
public static void EqAry(Object[] expd, Object[] actl) {EqAry(TypeIds.IdObj, expd, actl, "");}
public static void EqAry(int[] expd, int[] actl) {EqAry(TypeIds.IdInt, expd, actl, "");}
public static void EqAry(String[] expd, String[] actl) {EqAry(TypeIds.IdBry, BryUtl.Ary(expd), BryUtl.Ary(actl), "noMsg");}
private static void EqAry(int typeTid, Object expdAry, Object actlAry, String msgFmt, Object... msgArgs) {
boolean[] failures = CalcFailures(typeTid, expdAry, actlAry);
if (failures != null) {
WriteFailHead(bfr, msgFmt, msgArgs);
WriteFailBody(bfr, failures, typeTid, expdAry, actlAry);
throw ErrUtl.NewMsg(bfr.ToStrAndClear());
}
}
private static boolean[] CalcFailures(int tid, Object expdAry, Object actlAry) {
int expdLen = ArrayUtl.Len(expdAry);
int actlLen = ArrayUtl.Len(actlAry);
int maxLen = expdLen > actlLen ? expdLen : actlLen;
if (maxLen == 0) return null; // exit early if both arys are empty
boolean[] rv = null;
for (int i = 0; i < maxLen; i++) {
Object expdObj = i < expdLen ? ArrayUtl.GetAt(expdAry, i) : null;
Object actlObj = i < actlLen ? ArrayUtl.GetAt(actlAry, i) : null;
boolean eq = false;
if (expdObj == null && actlObj == null) eq = true;
else if (expdObj == null || actlObj == null) eq = false;
else {
switch (tid) {
case TypeIds.IdBool: eq = BoolUtl.Cast(expdObj) == BoolUtl.Cast(actlObj); break;
case TypeIds.IdLong: eq = LongUtl.Cast(expdObj) == LongUtl.Cast(actlObj); break;
case TypeIds.IdInt: eq = IntUtl.Cast(expdObj) == IntUtl.Cast(actlObj); break;
case TypeIds.IdByte: eq = ByteUtl.Cast(expdObj) == ByteUtl.Cast(actlObj); break;
case TypeIds.IdBry: eq = BryUtl.Eq((byte[])expdObj, (byte[])actlObj); break;
case TypeIds.IdObj: eq = ObjectUtl.Eq(expdObj, actlObj); break;
}
}
if (!eq) {
if (rv == null) {
rv = new boolean[maxLen];
}
rv[i] = true;
}
}
return rv;
}
private static void WriteFailHead(GfoStrBldr bfr, String msgFmt, Object[] msgArgs) {
bfr.Add(SectionBgn);
if (msgFmt != null) {
bfr.Add(StringUtl.Format(msgFmt, msgArgs));
bfr.Add(SectionMid);
}
}
private static void WriteFailBody(GfoStrBldr bfr, boolean[] failures, int typeId, Object expdAry, Object actlAry) {
int len = failures.length;
int expdLen = ArrayUtl.Len(expdAry);
int actlLen = ArrayUtl.Len(actlAry);
for (int i = 0; i < len; i++) {
boolean failure = failures[i];
int padLen = 5 - IntUtl.CountDigits(i); // 5=assuming no more than 9999 failures in one test
bfr.AddIntPadBgn(CharCode.Num0, padLen, i).AddCharColon().AddCharSpace();
WriteFailItm(bfr, typeId, expdAry, expdLen, i);
if (failure) {
bfr.Add(EqN).AddCharRepeat(CharCode.Space, padLen - 1);
WriteFailItm(bfr, typeId, actlAry, actlLen, i);
}
}
bfr.Add(SectionEnd);
}
private static void WriteFailItm(GfoStrBldr bfr, int typeId, Object ary, int len, int idx) {
if (idx < len) {
Object val = ArrayUtl.GetAt(ary, idx);
switch (typeId) {
case TypeIds.IdBool: bfr.AddBoolAsYn(BoolUtl.Cast(val)); break;
case TypeIds.IdBry: bfr.AddBry((byte[])val); break;
case TypeIds.IdLong: bfr.AddLong(LongUtl.Cast(val)); break;
case TypeIds.IdInt: bfr.AddInt(IntUtl.Cast(val)); break;
case TypeIds.IdByte: bfr.AddInt((int)(ByteUtl.Cast(val))); break;
case TypeIds.IdObj: bfr.Add(ObjectUtl.ToStr(val)); break;
default: throw ErrUtl.NewUnhandledDefault(typeId);
}
}
else
bfr.Add(Null);
bfr.AddCharNl();
}
private static void WriteAndThrow(String expd, String actl, String msgFmt, Object... msgArgs) {
WriteFailHead(bfr, msgFmt, msgArgs);
bfr.Add("expd: ").Add(expd).AddCharNl();
bfr.Add("actl: ").Add(actl).AddCharNl();
bfr.Add(SectionEnd);
throw ErrUtl.NewMsg(bfr.ToStrAndClear());
}
}

View File

@@ -0,0 +1,77 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.arrays;
import gplx.types.errs.ErrUtl;
public class IntAry {
private int max;
public IntAry(int max) {
this.len = 0;
this.max = max;
this.ary = new int[max];
}
public int Len() {return len;} private int len;
public int[] Ary() {return ary;} private int[] ary;
public void Clear() {
for (int i = 0; i < len; ++i)
ary[i] = 0;
len = 0;
}
public int GetAt(int i) {
if (i > -1 && i < len)
return ary[i];
else
throw ErrUtl.NewArgs("index is invalid", "i", i, "len", len);
}
public void Add(int v) {
if (len == max) {
int newMax = max * 2;
int[] newAry = new int[newMax];
for (int i = 0; i < len; ++i)
newAry[i] = ary[i];
this.ary = newAry;
this.max = newMax;
}
ary[len] = v;
++len;
}
public int PopOrFail() {
if (len == 0) throw ErrUtl.NewArgs("stack is empty");
return PopOr(-1);
}
public int PopOr(int or) {
if (len == 0) return or;
int rv = ary[len - 1];
--len;
return rv;
}
public int IdxOf(int find) {
for (int i = len - 1; i > -1; --i) {
if (ary[i] == find)
return i;
}
return NotFound;
}
public boolean DelFromEnd(int find) {
int findIdx = IdxOf(find); if (findIdx == NotFound) return false;
int lastIdx = len - 1;
for (int i = findIdx; i < lastIdx; ++i)
ary[i] = ary[i + 1];
ary[lastIdx] = 0;
--len;
return true;
}
public static final int NotFound = -1;
}

View File

@@ -0,0 +1,172 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.arrays;
import gplx.types.commons.lists.GfoListBase;
import gplx.types.basics.constants.AsciiByte;
import gplx.types.basics.strings.bfrs.GfoStringBldr;
import gplx.types.basics.utls.ArrayUtl;
import gplx.types.basics.utls.BryUtl;
import gplx.types.basics.utls.IntUtl;
import gplx.types.basics.utls.StringUtl;
public class IntAryUtl {
public static final int[] Empty = new int[0];
public static int[] New(int... v) {return v;}
public static void CopyTo(int[] src, int src_len, int[] trg) {
for (int i = 0; i < src_len; ++i)
trg[i] = src[i];
}
public static int[] Mid(int[] src, int bgn, int end) {
int len = end - bgn + 1;
int[] rv = new int[len];
for (int i = 0; i < len; i++) {
rv[i] = src[i + bgn];
}
return rv;
}
public static String ToStr(String spr, int... ary) {
GfoStringBldr sb = new GfoStringBldr();
int len = ary.length;
for (int i = 0; i < len; ++i) {
if (i != 0) sb.Add(spr);
int itm = ary[i];
sb.Add(itm);
}
return sb.ToStrAndClear();
}
public static int[] Parse(String raw, String spr) {
String[] ary = StringUtl.Split(raw, spr);
int len = ary.length;
int[] rv = new int[len];
for (int i = 0; i < len; i++)
rv[i] = IntUtl.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 = BryUtl.NewA7(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 ? AsciiByte.Comma : raw_bry[i];
switch (b) {
case AsciiByte.Num0: case AsciiByte.Num1: case AsciiByte.Num2: case AsciiByte.Num3: case AsciiByte.Num4:
case AsciiByte.Num5: case AsciiByte.Num6: case AsciiByte.Num7: case AsciiByte.Num8: case AsciiByte.Num9:
if (signed) return or;
cur_val += (b - AsciiByte.Num0) * cur_mult;
cur_mult *= 10;
break;
case AsciiByte.Space: case AsciiByte.Nl: case AsciiByte.Cr: case AsciiByte.Tab:
break;
case AsciiByte.Comma:
if (cur_idx < 0) return or;
rv[cur_idx--] = cur_val;
cur_val = 0; cur_mult = 1;
signed = false;
break;
case AsciiByte.Dash:
if (signed) return or;
cur_val *= -1;
signed = true;
break;
case AsciiByte.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[] ParseOr(byte[] src, int[] or) {
try {
if (BryUtl.IsNullOrEmpty(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 = IntUtl.MinValue;
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 = BryUtl.ToIntOr(src, num_bgn, num_end, IntUtl.MinValue);
if (num == IntUtl.MinValue) 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 + GfoListBase.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[])ArrayUtl.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 = IntUtl.MinValue;
if (pos_is_last) break;
}
byte b = src[pos];
switch (b) {
case AsciiByte.Num0: case AsciiByte.Num1: case AsciiByte.Num2: case AsciiByte.Num3: case AsciiByte.Num4:
case AsciiByte.Num5: case AsciiByte.Num6: case AsciiByte.Num7: case AsciiByte.Num8: case AsciiByte.Num9:
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 AsciiByte.Space: case AsciiByte.Tab: case AsciiByte.Nl: case AsciiByte.Cr: // NOTE: parseNumList replaces ws with '', so "1 1" will become "11"
break;
case AsciiByte.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 AsciiByte.Dash:
if (pos == raw_len -1) return or; // eos; EX: "1-"
if (num_bgn == -1) return or; // no rng_bgn; EX: "-2"
rng_bgn = BryUtl.ToIntOr(src, num_bgn, pos, IntUtl.MinValue);
if (rng_bgn == IntUtl.MinValue) 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[])ArrayUtl.Resize(rv, rv_idx);
} catch (Exception e) {return or;}
}
}

View File

@@ -0,0 +1,58 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.arrays;
import gplx.types.basics.utls.BryUtl;
import gplx.frameworks.tests.GfoTstr;
import gplx.types.basics.utls.IntUtl;
import org.junit.Test;
public class IntAryUtlTest {
private final IntAryTstr tstr = new IntAryTstr();
@Test public void Parse() {
tstr.TestParse("1,2,3" , 3, IntAryUtl.Empty, 1, 2, 3);
tstr.TestParse("123,321,213" , 3, IntAryUtl.Empty, 123, 321, 213);
tstr.TestParse(" 1, 2,3" , 3, IntAryUtl.Empty, 1, 2, 3);
tstr.TestParse("-1,+2,-3" , 3, IntAryUtl.Empty, -1, 2, -3);
tstr.TestParse(IntUtl.ToStr(IntUtl.MinValue) , 1, IntAryUtl.Empty, IntUtl.MinValue);
tstr.TestParse(IntUtl.ToStr(IntUtl.MaxValue) , 1, IntAryUtl.Empty, IntUtl.MaxValue);
tstr.TestParse("1,2" , 1, IntAryUtl.Empty);
tstr.TestParse("1" , 2, IntAryUtl.Empty);
tstr.TestParse("a" , 1, IntAryUtl.Empty);
tstr.TestParse("1-2," , 1, IntAryUtl.Empty);
}
@Test public void ParseOr() {
tstr.TestParseOr("1", 1);
tstr.TestParseOr("123", 123);
tstr.TestParseOr("1,2,123", 1, 2, 123);
tstr.TestParseOr("1,2,12,123", 1, 2, 12, 123);
tstr.TestParseOr("1-5", 1, 2, 3, 4, 5);
tstr.TestParseOr("1-1", 1);
tstr.TestParseOr("1-3,7,11-13,21", 1, 2, 3, 7, 11, 12, 13, 21);
tstr.TestParseOrEmpty("1 2"); // NOTE: MW would gen 12; treat as invalid
tstr.TestParseOrEmpty("1,"); // eos
tstr.TestParseOrEmpty("1,,2"); // empty comma
tstr.TestParseOrEmpty("1-"); // eos
tstr.TestParseOrEmpty("3-1"); // bgn > end
tstr.TestParseOrEmpty("1,a,2");
tstr.TestParseOrEmpty("a-1,2");
tstr.TestParseOrEmpty("-1"); // no rng bgn
}
}
class IntAryTstr {
public void TestParse(String raw, int reqd_len, int[] or, int... expd) {GfoTstr.EqAry(expd, IntAryUtl.Parse(raw, reqd_len, or), "failed to parse: {0}", raw);}
public void TestParseOrEmpty(String raw) {GfoTstr.EqAry(IntAryUtl.Empty, IntAryUtl.ParseOr(BryUtl.NewA7(raw), IntAryUtl.Empty));}
public void TestParseOr(String raw, int... expd) {GfoTstr.EqAry(expd , IntAryUtl.ParseOr(BryUtl.NewA7(raw), IntAryUtl.Empty));}
}

View File

@@ -13,19 +13,15 @@ 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.objects.primitives;
import gplx.objects.ObjectUtl;
import gplx.objects.errs.ErrUtl;
public class LongUtl {
public static final String ClsValName = "long";
public static final Class<?> ClsRefType = Long.class;
public static long Cast(Object o) {
try {
return (Long)o;
}
catch(Exception e) {
throw ErrUtl.NewFmt(e, "failed to cast to long; obj={0}", ObjectUtl.ToStr(o));
}
package gplx.types.basics.arrays;
public class ObjAry {
private ObjAry(Object[] ary) {
this.ary = ary;
}
public static String ToStr(long v) {return new Long(v).toString();}
public Object[] Ary() {return ary;} private final Object[] ary;
public Object GetAt(int i) {return ary[i];}
public Object GetAt0() {return ary[0];}
public Object GetAt1() {return ary[1];}
public static ObjAry New(Object... ary) {return new ObjAry(ary);}
public static ObjAry NewPair(Object val0, Object val1) {return new ObjAry(new Object[] {val0, val1});}
}

View File

@@ -13,8 +13,8 @@ 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.objects.strings;
import gplx.objects.errs.ErrUtl;
package gplx.types.basics.constants;
import gplx.types.errs.ErrUtl;
public class AsciiByte {
public static final byte
Null = 0 , Backfeed = 8, Tab = 9,

View File

@@ -13,7 +13,7 @@ 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.objects.primitives;
package gplx.types.basics.constants;
public class CharCode {
public static final char
NewLine = '\n',

View File

@@ -0,0 +1,159 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.encoders;
import gplx.types.basics.constants.AsciiByte;
import gplx.types.basics.utls.BryUtl;
import gplx.types.basics.utls.ByteUtl;
import gplx.types.basics.utls.IntUtl;
import gplx.types.basics.utls.StringUtl;
import gplx.types.errs.ErrUtl;
public class HexUtl {
public static int ParseOr(byte[] src, int or) {return ParseOr(src, 0, src.length, or);}
public static int ParseOr(byte[] src, int bgn, int end, int or) {
int rv = 0; int factor = 1;
byte b;
for (int i = end - 1; i >= bgn; i--) {
switch (src[i]) {
case AsciiByte.Num0: b = 0; break; case AsciiByte.Num1: b = 1; break; case AsciiByte.Num2: b = 2; break; case AsciiByte.Num3: b = 3; break; case AsciiByte.Num4: b = 4; break;
case AsciiByte.Num5: b = 5; break; case AsciiByte.Num6: b = 6; break; case AsciiByte.Num7: b = 7; break; case AsciiByte.Num8: b = 8; break; case AsciiByte.Num9: b = 9; break;
case AsciiByte.Ltr_A: b = 10; break; case AsciiByte.Ltr_B: b = 11; break; case AsciiByte.Ltr_C: b = 12; break; case AsciiByte.Ltr_D: b = 13; break; case AsciiByte.Ltr_E: b = 14; break; case AsciiByte.Ltr_F: b = 15; break;
case AsciiByte.Ltr_a: b = 10; break; case AsciiByte.Ltr_b: b = 11; break; case AsciiByte.Ltr_c: b = 12; break; case AsciiByte.Ltr_d: b = 13; break; case AsciiByte.Ltr_e: b = 14; break; case AsciiByte.Ltr_f: b = 15; break;
default: b = ByteUtl.MaxValue127; break;
}
if (b == ByteUtl.MaxValue127) return or;
rv += b * factor;
factor *= 16;
}
return rv;
}
public static int Parse(String src) {
int rv = ParseOr(src, -1); if (rv == -1) throw ErrUtl.NewParse("hexstring","src");
return rv;
}
public static int ParseOr(String src, int or) {
int rv = 0; int digit = 0, factor = 1, len = StringUtl.Len(src);
for (int i = len - 1; i > -1; --i) {
digit = ToInt(StringUtl.CharAt(src, i));
if (digit == -1) return or;
rv += digit * factor;
factor *= 16;
}
return rv;
}
public static byte[] ParseHexToBry(String src) {return ParseHexToBry(BryUtl.NewU8(src));}
public static byte[] ParseHexToBry(byte[] src) {
int src_len = src.length;
if ((src_len % 2) != 0) throw ErrUtl.NewArgs("hex_utl: hex_string must have an even length; src=~{0}", src);
int ary_len = src_len / 2;
byte[] rv = new byte[ary_len];
int rv_idx = 0;
for (int i = 0; i < src_len; i += 2) {
int val = ParseOr(src, i, i + 2, -1);
if (val == -1) throw ErrUtl.NewArgs("hex_utl: hex_string has invalid char; src=~{0}", src);
rv[rv_idx] = (byte)val;
rv_idx++;
}
return rv;
}
public static byte[] EncodeBry(byte[] src) {
int src_len = src.length;
byte[] trg = new byte[src_len * 2];
EncodeBry(src, trg);
return trg;
}
public static void EncodeBry(byte[] src, byte[] trg) {
int src_len = src.length, trg_len = trg.length;
if (trg_len != src_len * 2) throw ErrUtl.NewArgs("hex", "trg.len must be src.len * 2", "src_len", src_len, "trg_len", trg_len);
int trg_idx = -1;
for (int src_idx = 0; src_idx < src_len; ++src_idx) {
byte src_byte = src[src_idx];
trg[++trg_idx] = ToByteLcase(0xf & src_byte >>> 4);
trg[++trg_idx] = ToByteLcase(0xf & src_byte);
}
}
public static String ToStr(int val, int pad) {
char[] ary = new char[8]; int idx = 8; // 8 is max len of hexString; (2^4 * 8); EX: int.MaxValue = 7FFFFFFF
do {
int byt = val % 16;
ary[--idx] = ToChar(byt);
val /= 16;
} while (val > 0);
while (8 - idx < pad) // pad left with zeros
ary[--idx] = '0';
return StringUtl.NewCharAry(ary, idx, 8-idx);
}
public static void Write(byte[] bry, int bgn, int end, int val) {
for (int i = end - 1; i > bgn - 1; i--) {
int b = val % 16;
bry[i] = ToByteUcase(b);
val /= 16;
if (val == 0) break;
}
}
public static boolean IsHexMany(byte... ary) {
for (byte itm : ary) {
if (!IsHex(itm))
return false;
}
return true;
}
public static boolean IsHex(byte itm) {
switch (itm) {
case AsciiByte.Num0: case AsciiByte.Num1: case AsciiByte.Num2: case AsciiByte.Num3: case AsciiByte.Num4:
case AsciiByte.Num5: case AsciiByte.Num6: case AsciiByte.Num7: case AsciiByte.Num8: case AsciiByte.Num9:
case AsciiByte.Ltr_A: case AsciiByte.Ltr_B: case AsciiByte.Ltr_C: case AsciiByte.Ltr_D: case AsciiByte.Ltr_E: case AsciiByte.Ltr_F:
case AsciiByte.Ltr_a: case AsciiByte.Ltr_b: case AsciiByte.Ltr_c: case AsciiByte.Ltr_d: case AsciiByte.Ltr_e: case AsciiByte.Ltr_f:
return true;
default:
return false;
}
}
private static int ToInt(char c) {
switch (c) {
case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4;
case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9;
case 'A': return 10; case 'B': return 11; case 'C': return 12; case 'D': return 13; case 'E': return 14; case 'F': return 15;
case 'a': return 10; case 'b': return 11; case 'c': return 12; case 'd': return 13; case 'e': return 14; case 'f': return 15;
default: return -1;
}
}
private static char ToChar(int val) {
switch (val) {
case 0: return '0'; case 1: return '1'; case 2: return '2'; case 3: return '3'; case 4: return '4';
case 5: return '5'; case 6: return '6'; case 7: return '7'; case 8: return '8'; case 9: return '9';
case 10: return 'A'; case 11: return 'B'; case 12: return 'C'; case 13: return 'D'; case 14: return 'E'; case 15: return 'F';
default: throw ErrUtl.NewParse("hexstring", IntUtl.ToStr(val));
}
}
protected static byte ToByteUcase(int v) {
switch (v) {
case 0: return AsciiByte.Num0; case 1: return AsciiByte.Num1; case 2: return AsciiByte.Num2; case 3: return AsciiByte.Num3; case 4: return AsciiByte.Num4;
case 5: return AsciiByte.Num5; case 6: return AsciiByte.Num6; case 7: return AsciiByte.Num7; case 8: return AsciiByte.Num8; case 9: return AsciiByte.Num9;
case 10: return AsciiByte.Ltr_A; case 11: return AsciiByte.Ltr_B; case 12: return AsciiByte.Ltr_C; case 13: return AsciiByte.Ltr_D; case 14: return AsciiByte.Ltr_E; case 15: return AsciiByte.Ltr_F;
default: throw ErrUtl.NewParse("hexstring", IntUtl.ToStr(v));
}
}
protected static byte ToByteLcase(int v) {
switch (v) {
case 0: return AsciiByte.Num0; case 1: return AsciiByte.Num1; case 2: return AsciiByte.Num2; case 3: return AsciiByte.Num3;
case 4: return AsciiByte.Num4; case 5: return AsciiByte.Num5; case 6: return AsciiByte.Num6; case 7: return AsciiByte.Num7;
case 8: return AsciiByte.Num8; case 9: return AsciiByte.Num9; case 10: return AsciiByte.Ltr_a; case 11: return AsciiByte.Ltr_b;
case 12: return AsciiByte.Ltr_c; case 13: return AsciiByte.Ltr_d; case 14: return AsciiByte.Ltr_e; case 15: return AsciiByte.Ltr_f;
default: throw ErrUtl.NewParse("hexstring", IntUtl.ToStr(v));
}
}
}

View File

@@ -0,0 +1,76 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.encoders;
import gplx.frameworks.tests.GfoTstr;
import gplx.types.basics.utls.BryUtl;
import gplx.types.basics.utls.ByteUtl;
import gplx.types.basics.utls.IntUtl;
import gplx.types.basics.utls.StringUtl;
import org.junit.Test;
public class HexUtlTest {
private final HexUtlTstr tstr = new HexUtlTstr();
@Test public void To_int() {
tstr.TestParse("0" , 0);
tstr.TestParse("F" , 15);
tstr.TestParse("0F" , 15);
tstr.TestParse("10" , 16);
tstr.TestParse("20" , 32);
tstr.TestParse("FF" , 255);
tstr.TestParse("100" , 256);
tstr.TestParse("0a" , 10);
tstr.TestParse("7FFFFFFF" , IntUtl.MaxValue);
tstr.TestParseOr("100" , 256);
}
@Test public void To_str() {
tstr.TestToStr(0 , "0");
tstr.TestToStr(15 , "F");
tstr.TestToStr(16 , "10");
tstr.TestToStr(32 , "20");
tstr.TestToStr(255 , "FF");
tstr.TestToStr(IntUtl.MaxValue, "7FFFFFFF");
tstr.TestToStr(15, 2 , "0F");
tstr.TestToStr(15, 3 , "00F");
}
@Test public void Write() {
tstr.TestWrite("[00000000]", 1, 9, 15, "[0000000F]");
tstr.TestWrite("[00000000]", 1, 9, 255, "[000000FF]");
}
@Test public void Encode() {
tstr.TestParseHexToBry("E2A7BC", 226, 167, 188);
}
}
class HexUtlTstr {
public void TestWrite(String s, int bgn, int end, int val, String expd) {
byte[] bry = BryUtl.NewA7(s);
HexUtl.Write(bry, bgn, end, val);
GfoTstr.Eq(expd, StringUtl.NewA7(bry));
}
public void TestParse(String raw, int expd) {
int actl = HexUtl.Parse(raw);
GfoTstr.Eq(expd, actl);
}
public void TestParseOr(String raw, int expd) {GfoTstr.Eq(expd, HexUtl.ParseOr(BryUtl.NewA7(raw), -1));}
public void TestToStr(int val, String expd) {TestToStr(val, 0, expd);}
public void TestToStr(int val, int pad, String expd) {
String actl = HexUtl.ToStr(val, pad);
GfoTstr.Eq(expd, actl);
}
public void TestParseHexToBry(String val, int... expd) {
byte[] actl = HexUtl.ParseHexToBry(BryUtl.NewU8(val));
GfoTstr.EqAry(ByteUtl.AryByInts(expd), actl, "encode");
}
}

View File

@@ -0,0 +1,106 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.strings.bfrs;
import gplx.types.basics.constants.AsciiByte;
import gplx.types.basics.constants.CharCode;
import gplx.types.basics.strings.unicodes.Utf16Utl;
import gplx.types.basics.utls.BoolUtl;
import gplx.types.basics.utls.IntUtl;
import gplx.types.basics.utls.StringUtl;
public class GfoStringBldr extends StringBuilderLni {
public boolean HasNone() {return this.Len() == 0;}
public boolean HasSome() {return this.Len() > 0;}
public GfoStringBldr Clear() {LniDel(0, this.Len()); return this;}
public GfoStringBldr AddFmt(String format, Object... args) {LniAdd(StringUtl.Format(format, args)); return this;}
public GfoStringBldr Add(byte[] v) {
if (v != null)
this.LniAdd(StringUtl.NewU8(v));
return this;
}
public GfoStringBldr AddChar(char v) {this.LniAddChar(v); return this;}
public GfoStringBldr AddByte(byte v) {this.LniAddByte(v); return this;}
public GfoStringBldr Add(int v) {this.LniAdd(v); return this;}
public GfoStringBldr Add(String v) {this.LniAdd(v); return this;}
public GfoStringBldr AddLong(long v) {this.LniAddLong(v); return this;}
public GfoStringBldr AddObj(Object v) {this.LniAddObj(v); return this;}
public GfoStringBldr AddMid(String v, int bgn) {this.LniAddMid(v, bgn, v.length()); return this;}
public GfoStringBldr AddMid(String v, int bgn, int len) {this.LniAddMid(v, bgn, len); return this;}
public GfoStringBldr AddBool(boolean val) {
this.LniAdd(val ? BoolUtl.TrueStr : BoolUtl.FalseStr);
return this;
}
public GfoStringBldr AddBoolAsYn(boolean val) {
this.LniAdd(val ? "y" : "n");
return this;
}
public GfoStringBldr AddCharNl() {return AddChar(CharCode.NewLine);}
public GfoStringBldr AddCharSpace() {return AddChar(CharCode.Space);}
public GfoStringBldr AddCharColon() {return AddChar(CharCode.Colon);}
public GfoStringBldr AddCharRepeat(char c, int repeat) {
this.LniEnsureCapacity(this.Len() + repeat);
for (int i = 0; i < repeat; i++)
AddChar(c);
return this;
}
public GfoStringBldr AddByteRepeat(byte c, int repeat) {
this.LniEnsureCapacity(this.Len() + repeat);
for (int i = 0; i < repeat; i++)
AddByte(c);
return this;
}
public GfoStringBldr AddCharByCode(int code) {
if (code >= Utf16Utl.SurrogateCpBgn && code <= Utf16Utl.SurrogateCpEnd) {
this.LniAddChar((char)((code - 0x10000) / 0x400 + 0xD800));
this.LniAddChar((char)((code - 0x10000) % 0x400 + 0xDC00));
}
else {
this.LniAddChar((char)code);
}
return this;
}
public GfoStringBldr AddIntPadBgn(char padChar, int strLen, int val) {
int digitLen = IntUtl.CountDigits(val);
int padLen = strLen - digitLen;
if (padLen > 0) // note that this skips padLen == 0, as well as guarding against negative padLen; EX: pad(" ", 3, 1234) -> "1234"
AddCharRepeat(padChar, padLen);
Add(val);
return this;
}
public GfoStringBldr AddIntFixed(int val, int digits) {return AddIntPad(val, IntUtl.Log10(val), digits);}
public GfoStringBldr AddIntPad(int val, int valLog, int arySlots) {
if (val < 0) {
AddCharByCode(AsciiByte.Dash);
val *= -1; // make positive
valLog *= -1; // valLog will be negative; make positive
arySlots -= 1; // reduce slot by 1
}
if (valLog >= arySlots) {
val %= IntUtl.Log10Vals[arySlots];
}
for (int i = 0; i < arySlots; i++) {
int logIdx = arySlots - i - 1;
int div = logIdx < IntUtl.Log10ValsLen ? IntUtl.Log10Vals[logIdx] : IntUtl.MaxValue;
AddCharByCode((byte)((val / div) + 48));
val %= div;
}
return this;
}
public String ToStrAndClear() {
String rv = ToStr();
Clear();
return rv;
}
}

View File

@@ -0,0 +1,17 @@
package gplx.types.basics.strings.bfrs;
import java.lang.StringBuilder;
public class StringBuilderLni {
private StringBuilder sb = new StringBuilder();
public final int Len() {return sb.length();}
protected final void LniDel(int bgn, int len) {sb.delete(bgn, len);}
protected final void LniAddByte(byte i) {sb.append(i);}
public final void LniAddChar(char c) {sb.append(c);}
protected final void LniAdd(int i) {sb.append(i);}
protected final void LniAddLong(long i) {sb.append(i);}
public final void LniAdd(String s) {sb.append(s);}
protected final void LniAddObj(Object o) {sb.append(o);}
protected final void LniAddMid(String s, int bgn, int len) {sb.append(s, bgn, len);}
protected final void LniEnsureCapacity(int capacity) {sb.ensureCapacity(capacity);}
public final String ToStr() {return sb.toString();}
@Override public final String toString() {return sb.toString();}
}

View File

@@ -13,7 +13,7 @@ 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.objects.strings.charSources;
package gplx.types.basics.strings.charSources;
public interface CharSource {
String Src();
int GetData(int pos);

View File

@@ -13,8 +13,8 @@ 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.objects.strings.charSources;
import gplx.objects.strings.StringUtl;
package gplx.types.basics.strings.charSources;
import gplx.types.basics.utls.StringUtl;
public class CharSourceUtl {
public static int IndexOfAny(String src, char[] ary) {
int srcLen = StringUtl.Len(src);

View File

@@ -13,10 +13,10 @@ 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.objects.strings.unicodes;
import gplx.objects.errs.ErrUtl;
import gplx.objects.strings.StringUtl;
import gplx.objects.strings.charSources.CharSource;
package gplx.types.basics.strings.unicodes;
import gplx.types.basics.strings.charSources.CharSource;
import gplx.types.basics.utls.StringUtl;
import gplx.types.errs.ErrUtl;
public interface Ustring extends CharSource {
int LenInChars();
int MapDataToChar(int pos);
@@ -65,11 +65,11 @@ class UstringCodepoints implements Ustring {
int codeIdx = 0;
for (int i = 0; i < charsLen; i++) {
char c = src.charAt(i);
if (c >= UstringUtl.SurrogateHiBgn && c <= UstringUtl.SurrogateHiEnd) { // character is 1st part of surrogate-pair
if (c >= Utf16Utl.SurrogateHiBgn && c <= Utf16Utl.SurrogateHiEnd) { // character is 1st part of surrogate-pair
i++;
if (i == charsLen) throw ErrUtl.NewFmt("invalid surrogate pair found; src={0}", src);
int c2 = src.charAt(i);
codes[codeIdx++] = UstringUtl.SurrogateCpBgn + (c - UstringUtl.SurrogateHiBgn) * UstringUtl.SurrogateRange + (c2 - UstringUtl.SurrogateLoBgn);
codes[codeIdx++] = Utf16Utl.SurrogateCpBgn + (c - Utf16Utl.SurrogateHiBgn) * Utf16Utl.SurrogateRange + (c2 - Utf16Utl.SurrogateLoBgn);
}
else {
codes[codeIdx++] = c;
@@ -81,13 +81,13 @@ class UstringCodepoints implements Ustring {
int len = 0;
for (int i = bgn; i < end; i++) {
int code = codes[i];
len += code >= UstringUtl.SurrogateCpBgn && code <= UstringUtl.SurrogateCpEnd ? 2 : 1;
len += code >= Utf16Utl.SurrogateCpBgn && code <= Utf16Utl.SurrogateCpEnd ? 2 : 1;
}
char[] rv = new char[len];
int rvIdx = 0;
for (int i = bgn; i < end; i++) {
int code = codes[i];
if (code >= UstringUtl.SurrogateCpBgn && code <= UstringUtl.SurrogateCpEnd) {
if (code >= Utf16Utl.SurrogateCpBgn && code <= Utf16Utl.SurrogateCpEnd) {
rv[rvIdx++] = (char)((code - 0x10000) / 0x400 + 0xD800);
rv[rvIdx++] = (char)((code - 0x10000) % 0x400 + 0xDC00);
}
@@ -143,7 +143,7 @@ class UstringCodepoints implements Ustring {
// sum all items before requested pos
int rv = 0;
for (int i = 0; i < codePos; i++) {
rv += codes[i] < UstringUtl.SurrogateCpBgn ? 1 : 2;
rv += codes[i] < Utf16Utl.SurrogateCpBgn ? 1 : 2;
}
return rv;
}
@@ -154,7 +154,7 @@ class UstringCodepoints implements Ustring {
int rv = 0;
for (int i = 0; i < charPos; i++) {
char c = src.charAt(i);
if (c >= UstringUtl.SurrogateHiBgn && c <= UstringUtl.SurrogateHiEnd){ // SurrogateHi
if (c >= Utf16Utl.SurrogateHiBgn && c <= Utf16Utl.SurrogateHiEnd){ // SurrogateHi
if (i == charPos - 1) // charPos is SurrogateLo; return -1 since SurrogateLo doesn't map to a codePos
return -1;
}

View File

@@ -13,8 +13,8 @@ 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.objects.strings.unicodes;
import gplx.objects.errs.ErrUtl;
package gplx.types.basics.strings.unicodes;
import gplx.types.errs.ErrUtl;
public class UstringUtl {
public static Ustring NewCodepoints(String src) {
if (src == null) throw ErrUtl.NewNull("src");
@@ -31,7 +31,7 @@ public class UstringUtl {
int rv = 0;
for (int i = 0; i < srcLen; i++) {
char c = src.charAt(i);
if (c >= SurrogateHiBgn && c <= SurrogateHiEnd) {
if (c >= Utf16Utl.SurrogateHiBgn && c <= Utf16Utl.SurrogateHiEnd) {
i++;
}
rv++;
@@ -39,12 +39,4 @@ public class UstringUtl {
return rv;
}
public static final int // REF: https://en.wikipedia.org/wiki/Universal_Character_Set_characters
SurrogateHiBgn = 0xD800, // 55,296: Surrogate high start
SurrogateHiEnd = 0xDBFF, // 56,319: Surrogate high end
SurrogateLoBgn = 0xDC00, // 56,320: Surrogate low start
SurrogateLoEnd = 0xDFFF, // 57,343: Surrogate low end
SurrogateCpBgn = 0x010000, // 65,536: Surrogate codepoint start
SurrogateCpEnd = 0x10FFFF, // 1,114,111: Surrogate codepoint end
SurrogateRange = 0x400; // 1,024: Surrogate range (end - start) for high / low
}

View File

@@ -0,0 +1,139 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.strings.unicodes;
import gplx.types.basics.wrappers.IntRef;
import gplx.types.errs.ErrUtl;
public class Utf16Utl {
public static int SurrogateMerge(int hi, int lo) { // REF: http://perldoc.perl.org/Encode/Unicode.html
return 0x10000 + (hi - 0xD800) * 0x400 + (lo - 0xDC00);
}
public static void SurrogateSplit(int v, IntRef hi, IntRef lo) {
hi.ValSet((v - 0x10000) / 0x400 + 0xD800);
lo.ValSet((v - 0x10000) % 0x400 + 0xDC00);
}
public static int DecodeToInt(byte[] ary, int pos) {
byte b0 = ary[pos];
if ((b0 & 0x80) == 0) {
return b0;
}
else if ((b0 & 0xE0) == 0xC0) {
return ( b0 & 0x1f) << 6
| ( ary[pos + 1] & 0x3f)
;
}
else if ((b0 & 0xF0) == 0xE0) {
return ( b0 & 0x0f) << 12
| ((ary[pos + 1] & 0x3f) << 6)
| ( ary[pos + 2] & 0x3f)
;
}
else if ((b0 & 0xF8) == 0xF0) {
return ( b0 & 0x07) << 18
| ((ary[pos + 1] & 0x3f) << 12)
| ((ary[pos + 2] & 0x3f) << 6)
| ( ary[pos + 3] & 0x3f)
;
}
else
throw ErrUtl.NewArgs("invalid utf8 byte", "byte", b0);
}
public static byte[] EncodeIntToBry(int c) {
int bry_len = LenByInt(c);
byte[] bry = new byte[bry_len];
EncodeInt(c, bry, 0);
return bry;
}
public static int EncodeChar(int c, char[] c_ary, int c_pos, byte[] b_ary, int b_pos) {
if ((c > -1)
&& (c < 128)) {
b_ary[ b_pos] = (byte)c;
return 1;
}
else if (c < 2048) {
b_ary[ b_pos] = (byte)(0xC0 | (c >> 6));
b_ary[++b_pos] = (byte)(0x80 | (c & 0x3F));
return 1;
}
else if((c > 55295) // 0xD800
&& (c < 56320)) { // 0xDFFF
if (c_pos >= c_ary.length) throw ErrUtl.NewArgs("incomplete surrogate pair at end of String", "char", c);
char nxt_char = c_ary[c_pos + 1];
int v = SurrogateMerge(c, nxt_char);
b_ary[b_pos] = (byte)(0xF0 | (v >> 18));
b_ary[++b_pos] = (byte)(0x80 | (v >> 12) & 0x3F);
b_ary[++b_pos] = (byte)(0x80 | (v >> 6) & 0x3F);
b_ary[++b_pos] = (byte)(0x80 | (v & 0x3F));
return 2;
}
else {
b_ary[b_pos] = (byte)(0xE0 | (c >> 12));
b_ary[++b_pos] = (byte)(0x80 | (c >> 6) & 0x3F);
b_ary[++b_pos] = (byte)(0x80 | (c & 0x3F));
return 1;
}
}
public static int EncodeInt(int c, byte[] src, int pos) {
if ((c > -1)
&& (c < 128)) {
src[ pos] = (byte)c;
return 1;
}
else if (c < 2048) {
src[ pos] = (byte)(0xC0 | (c >> 6));
src[++pos] = (byte)(0x80 | (c & 0x3F));
return 2;
}
else if (c < 65536) {
src[pos] = (byte)(0xE0 | (c >> 12));
src[++pos] = (byte)(0x80 | (c >> 6) & 0x3F);
src[++pos] = (byte)(0x80 | (c & 0x3F));
return 3;
}
else if (c < 2097152) {
src[pos] = (byte)(0xF0 | (c >> 18));
src[++pos] = (byte)(0x80 | (c >> 12) & 0x3F);
src[++pos] = (byte)(0x80 | (c >> 6) & 0x3F);
src[++pos] = (byte)(0x80 | (c & 0x3F));
return 4;
}
else throw ErrUtl.NewArgs("UTF-16 int must be between 0 and 2097152", "char", c);
}
private static int LenByInt(int c) {
if ((c > -1)
&& (c < 128)) return 1; // 1 << 7
else if (c < 2048) return 2; // 1 << 11
else if (c < 65536) return 3; // 1 << 16
else if (c < 2097152) return 4;
else throw ErrUtl.NewArgs("UTF-16 int must be between 0 and 2097152", "char", c);
}
public static int LenByChar(int c) {
if ((c > -1)
&& (c < 128)) return 1; // 1 << 7
else if (c < 2048) return 2; // 1 << 11
else if ((c > 55295) // 0xD800
&& (c < 56320)) return 4; // 0xDFFF
else if (c < 65536) return 3; // 1 << 16
else throw ErrUtl.NewArgs("UTF-16 int must be between 0 and 65536", "char", c);
}
public static final int // REF: https://en.wikipedia.org/wiki/Universal_Character_Set_characters
SurrogateHiBgn = 0xD800, // 55,296: Surrogate high start
SurrogateHiEnd = 0xDBFF, // 56,319: Surrogate high end
SurrogateLoBgn = 0xDC00, // 56,320: Surrogate low start
SurrogateLoEnd = 0xDFFF, // 57,343: Surrogate low end
SurrogateCpBgn = 0x010000, // 65,536: Surrogate codepoint start
SurrogateCpEnd = 0x10FFFF, // 1,114,111: Surrogate codepoint end
SurrogateRange = 0x400; // 1,024: Surrogate range (end - start) for high / low
}

View File

@@ -0,0 +1,51 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.strings.unicodes;
import gplx.frameworks.tests.GfoTstr;
import gplx.types.basics.utls.BryUtl;
import gplx.types.basics.wrappers.IntRef;
import org.junit.Test;
public class Utf16UtlTest {
private Utf16UtlTstr tstr = new Utf16UtlTstr();
@Test public void EncodeDecode() {
tstr.TestEncodeDecode(162, 194, 162); // cent; ¢
tstr.TestEncodeDecode(8364, 226, 130, 172); // euro; €
tstr.TestEncodeDecode(150370, 240, 164, 173, 162); // example from [[UTF-8]]; should be encoded as two bytes; 𤭢
tstr.TestEncodeDecode(143489, 240, 163, 130, 129); // EX: 駣𣂁脁 DATE:2017-04-22; 𣂁
}
@Test public void Surrogate() {
tstr.TestSurrogate(0x64321, 0xD950, 0xDF21); // example from w:UTF-16
tstr.TestSurrogate(66643, 55297, 56403); // example from d:Boomerang
}
}
class Utf16UtlTstr {
private IntRef hiRef = IntRef.NewNeg1(), loRef = IntRef.NewNeg1();
public void TestEncodeDecode(int expd_c_int, int... expd_int) {
byte[] expd = BryUtl.NewByInts(expd_int);
byte[] bfr = new byte[10];
int bfr_len = Utf16Utl.EncodeInt(expd_c_int, bfr, 0);
byte[] actl = BryUtl.MidByLen(bfr, 0, bfr_len);
GfoTstr.Eq(expd, actl);
int actl_c_int = Utf16Utl.DecodeToInt(bfr, 0);
GfoTstr.Eq(expd_c_int, actl_c_int);
}
public void TestSurrogate(int v, int hi, int lo) {
GfoTstr.Eq(v, Utf16Utl.SurrogateMerge((char)hi, (char)lo));
Utf16Utl.SurrogateSplit(v, hiRef, loRef);
GfoTstr.Eq(hi, hiRef.Val());
GfoTstr.Eq(lo, loRef.Val());
}
}

View File

@@ -0,0 +1,192 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.strings.unicodes;
import gplx.types.basics.utls.BryLni;
import gplx.types.basics.utls.BryUtl;
import gplx.types.errs.ErrUtl;
import gplx.types.basics.utls.ByteUtl;
import gplx.types.basics.utls.IntUtl;
public class Utf8Utl {
public static int LenOfBry(byte[] ary) {
if (ary == null) return 0;
int rv = 0;
int pos = 0, len = ary.length;
while (pos < len) {
int char_len = LenOfCharBy1stByte(ary[pos]);
++rv;
pos += char_len;
}
return rv;
}
public static int LenOfCharBy1stByte(byte b) {// SEE:w:UTF-8
int i = b & 0xff; // PATCH.JAVA:need to convert to unsigned byte
switch (i) {
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15:
case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31:
case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47:
case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: case 59: case 60: case 61: case 62: case 63:
case 64: case 65: case 66: case 67: case 68: case 69: case 70: case 71: case 72: case 73: case 74: case 75: case 76: case 77: case 78: case 79:
case 80: case 81: case 82: case 83: case 84: case 85: case 86: case 87: case 88: case 89: case 90: case 91: case 92: case 93: case 94: case 95:
case 96: case 97: case 98: case 99: case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107: case 108: case 109: case 110: case 111:
case 112: case 113: case 114: case 115: case 116: case 117: case 118: case 119: case 120: case 121: case 122: case 123: case 124: case 125: case 126: case 127:
case 128: case 129: case 130: case 131: case 132: case 133: case 134: case 135: case 136: case 137: case 138: case 139: case 140: case 141: case 142: case 143:
case 144: case 145: case 146: case 147: case 148: case 149: case 150: case 151: case 152: case 153: case 154: case 155: case 156: case 157: case 158: case 159:
case 160: case 161: case 162: case 163: case 164: case 165: case 166: case 167: case 168: case 169: case 170: case 171: case 172: case 173: case 174: case 175:
case 176: case 177: case 178: case 179: case 180: case 181: case 182: case 183: case 184: case 185: case 186: case 187: case 188: case 189: case 190: case 191:
return 1;
case 192: case 193: case 194: case 195: case 196: case 197: case 198: case 199: case 200: case 201: case 202: case 203: case 204: case 205: case 206: case 207:
case 208: case 209: case 210: case 211: case 212: case 213: case 214: case 215: case 216: case 217: case 218: case 219: case 220: case 221: case 222: case 223:
return 2;
case 224: case 225: case 226: case 227: case 228: case 229: case 230: case 231: case 232: case 233: case 234: case 235: case 236: case 237: case 238: case 239:
return 3;
case 240: case 241: case 242: case 243: case 244: case 245: case 246: case 247:
return 4;
default: throw ErrUtl.NewArgs("invalid initial utf8 byte", "byte", b);
}
}
public static byte[] GetCharAtPosAsBry(byte[] bry, int pos) {
int len = LenOfCharBy1stByte(bry[pos]);
return BryLni.Mid(bry, pos, pos + len);
}
public static byte[] IncrementCharAtLastPos(byte[] bry) { // EX: abc -> abd; complexity is for multi-byte chars
int bry_len = bry.length; if (bry_len == 0) return bry;
int pos = bry_len - 1;
while (true) { // loop bwds
int cur_char_pos0 = GetPrvCharPos0Old(bry, pos); // get byte0 of char
int cur_char_len = (pos - cur_char_pos0) + 1; // calc len of char
int nxt_char = Codepoint_max;
if (cur_char_len == 1) { // len=1; just change 1 byte
nxt_char = IncrementChar(bry[cur_char_pos0]); // get next char
if (nxt_char < 128) { // single-byte char; just change pos
bry = BryUtl.Copy(bry); // always return new bry; never reuse existing
bry[cur_char_pos0] = (byte)nxt_char;
return bry;
}
}
int cur_char = Utf16Utl.DecodeToInt(bry, cur_char_pos0);
nxt_char = IncrementChar(cur_char);
if (nxt_char != IntUtl.MinValue) {
byte[] nxt_char_as_bry = Utf16Utl.EncodeIntToBry(nxt_char);
bry = BryUtl.Add(BryLni.Mid(bry, 0, cur_char_pos0), nxt_char_as_bry);
return bry;
}
pos = cur_char_pos0 - 1;
if (pos < 0) return null;
}
}
public static int GetPrvCharPos0Old(byte[] bry, int pos) { // find pos0 of char while moving bwd through bry; see test
int stop = pos - 4; // UTF8 char has max of 4 bytes
if (stop < 0) stop = 0; // if at pos 0 - 3, stop at 0
for (int i = pos - 1; i >= stop; i--) { // start at pos - 1, and move bwd; NOTE: pos - 1 to skip pos, b/c pos will never definitively yield any char_len info
byte b = bry[i];
int char_len = LenOfCharBy1stByte(b);
switch (char_len) { // if char_len is multi-byte and pos is at correct multi-byte pos (pos - i = # of bytes - 1), then pos0 found; EX: € = {226,130,172}; 172 is skipped; 130 has len of 1 -> continue; 226 has len of 3 and is found at correct pos for 3 byte char -> return
case 2: if (pos - i == 1) return i; break;
case 3: if (pos - i == 2) return i; break;
case 4: if (pos - i == 3) return i; break;
}
}
return pos; // no mult-byte char found; return pos
}
public static int GetPrvCharPos0(byte[] src, int cur) { // find pos0 of char while moving bwd through src; see test
// do bounds checks
if (cur == 0) return -1;
if (cur <= -1 || cur > src.length) throw ErrUtl.NewArgs("invalid index for get_prv_char_pos0", "src", src, "cur", cur);
// start at cur - 1; note bounds checks above
int pos = cur - 1;
// get 1st byte and check if ASCII for (a) error-checking (ASCII can only be in 1st byte); (b) performance
byte b = src[pos];
if (b >= 0 && b <= ByteUtl.MaxValue127) return pos;
// loop maximum of 4 times; note that UTF8 char has max of 4 bytes
for (int i = 0; i < 4; i++) {
int char_len = LenOfCharBy1stByte(b);
switch (char_len) { // if char_len is multi-byte and cur is at correct multi-byte pos (cur - i = # of bytes - 1), then pos0 found; EX: € = {226,130,172}; 172 is skipped; 130 has len of 1 -> continue; 226 has len of 3 and is found at correct cur for 3 byte char -> return
case 2: if (i == 1) return pos; break;
case 3: if (i == 2) return pos; break;
case 4: if (i == 3) return pos; break;
}
// decrement and set byte
pos--;
b = src[pos];
}
throw ErrUtl.NewArgs("could not get prv_char", "src", src, "cur", cur);
}
public static int IncrementChar(int cur) {
while (cur++ < Codepoint_max) {
if (cur == Codepoint_surrogate_bgn) cur = Codepoint_surrogate_end + 1; // skip over surrogate range
if (!CodepointValid(cur)) continue;
return cur;
}
return IntUtl.MinValue;
}
private static boolean CodepointValid(int v) {
return Character.isDefined(v);
}
public static final int
Codepoint_max = 0x10FFFF, //see http://unicode.org/glossary/
Codepoint_surrogate_bgn = 0xD800,
Codepoint_surrogate_end = 0xDFFF;
}
/*
== Definitions ==
=== a7 vs u8 ===
* a7 -> ASCII (7 bits)
* u8 -> UTF-8 (8 bytes)
In retrospect, better abbreviations would have been:
* ascii -> ASCII
* utf08 -> UTF-8
* utf16 -> UTF-16
=== General ===
==== Byte ====
* Standard definition; 8 bits (2^8 or 256)
==== Codepoint ====
* Represents 1 atomic character but can be composed of multiple bytes
** Examples:
<pre>
1 byte : "a" (letter a)
2 bytes: "¢" (cent)
3 bytes: "€" (euro)
4 bytes: "𤭢" (Chinese character)
</pre>
* Defined by unicode as a sequence of 4 hexadecimals (2 bytes) or 8 hexadecimals (4 bytes); REF:http://www.unicode.org
** 4 hexadecimal is 2 bytes (2^(4 * 4) -> 2^16)
==== char ====
* Java definition of a codepoint which is encoded as 2 bytes (2^16 or 65,536)
* For Western langauges: 1 codepoint equals 1 char (2 bytes);
** For example, chars like "a", "œ", "é" are 1 Java char
* For Eastern langauges: 1 codepoint can equal 2 chars (4 bytes);
** For example, chars like "駣" are 2 Java chars though they represent 1 conceptual codepoint (in English terms, "駣" is a single letter just like the letter "a")
==== Supplementary characters ====
* Represents a codepoint which is defined by 3 or 4 bytes
* Is defined by 1 surrogate pair
** lo-surrogate : 2 bytes
** hi-surrogate : 2 bytes
=== Conventions ===
* Codepoints will be rendered as one int (4 bytes), not 4 hexadecimals (1 byte) 8 hexadecimal (4 bytes)
* The "char" datatype will rarely be used in code; instead byte arrays or codepoint-ints will be used
* The "character" word will not be used in comments; instead the "codepoint" word will be used
*/

View File

@@ -0,0 +1,69 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.strings.unicodes;
import gplx.types.basics.utls.BryUtl;
import gplx.frameworks.tests.GfoTstr;
import gplx.types.basics.utls.ByteUtl;
import gplx.types.basics.utls.StringUtl;
import org.junit.Test;
public class Utf8UtlTest {
private Utf8UtlTstr tstr = new Utf8UtlTstr();
@Test public void Get_prv_char_pos0() {
tstr.TestGetPrvCharPos0("abcd", 3); // len=1; (note that bry.len = 4)
tstr.TestGetPrvCharPos0("a", 0); // len=1; short-String
tstr.TestGetPrvCharPos0("abc¢", 3); // len=2; (note that bry.len = 5)
tstr.TestGetPrvCharPos0("abc€", 3); // len=3; (note that bry.len = 6)
tstr.TestGetPrvCharPos0("abc" + StringUtl.NewU8(ByteUtl.AryByInts(240, 164, 173, 162)), 3); // len=4; (note that bry.len = 7)
}
@Test public void Increment_char_at_last_pos() {
tstr.TestIncrementCharAtLastPos("a", "b");
tstr.TestIncrementCharAtLastPos("abc", "abd");
tstr.TestIncrementCharAtLastPos("É", "Ê"); // len=2
tstr.TestIncrementCharAtLastPos("", ""); // len=3
}
// @Test public void Increment_char_at_last_pos_exhaustive_check() { // check all values; commented for perf
// Bry_bfr bfr = Bry_bfr_.New();
// int bgn = 32;
// while (true) {
// byte[] bgn_bry = Utf16_.Encode_int_to_bry(bgn);
// int end = Utf8_.Increment_char(bgn);
// if (end == Utf8_.Codepoint_max) break;
//// if (bgn > 1024 * 1024) break;
// byte[] end_by_codepoint_next = Utf16_.Encode_int_to_bry(end);
// byte[] end_by_increment_char = Utf8_.Increment_char_at_last_pos(bgn_bry);
// if (!Bry_.Eq(end_by_codepoint_next, end_by_increment_char)) {
// Tfds.Write(bgn);
// }
//// bfr .Add_int_variable(bgn).Add_byte(Byte_ascii.Tab)
//// .Add(bgn_bry).Add_byte(Byte_ascii.Tab)
//// .Add(end_by_codepoint_next).Add_byte(Byte_ascii.Tab)
//// .Add(end_by_increment_char).Add_byte(Byte_ascii.Tab)
//// .Add_byte_nl()
//// ;
// bgn = end;
// bgn_bry = end_by_codepoint_next;
// }
// Tfds.WriteText(bfr.To_str_and_clear());
// }
}
class Utf8UtlTstr {
public void TestGetPrvCharPos0(String srcStr, int expd) {
byte[] srcBry = BryUtl.NewU8(srcStr);
GfoTstr.Eq(expd, Utf8Utl.GetPrvCharPos0(srcBry, srcBry.length));
GfoTstr.Eq(expd, Utf8Utl.GetPrvCharPos0Old(srcBry, srcBry.length - 1));
}
public void TestIncrementCharAtLastPos(String str, String expd) {GfoTstr.Eq(expd, StringUtl.NewU8(Utf8Utl.IncrementCharAtLastPos(BryUtl.NewU8(str))));}
}

View File

@@ -0,0 +1,32 @@
package gplx.types.basics.utls;
import java.lang.System;
import java.lang.reflect.Array;
public class ArrayLni {
public static final Object Cast(Object o) {return o;} // NOTE: leftover from .NET; casts System.Object to System.Array
public static final int Len(Object ary) {return Array.getLength(ary);}
public static final Object GetAt(Object ary, int i) {return Array.get(ary, i);}
public static final void SetAt(Object ary, int i, Object o) {Array.set(ary, i, o);}
public static final Object Create(Class<?> c, int count) {return Array.newInstance(c, count);}
public static final Class<?> ComponentType(Object ary) {return ary.getClass().getComponentType();}
public static final void CopyTo(Object src, int srcBgn
, Object trg, int trgBgn, int srcLen) {System.arraycopy(src, srcBgn, trg, trgBgn, srcLen);}
public static final Object Resize(Object src, int trgLen) {
Object trg = Create(ComponentType(src), trgLen);
int srcLen = Len(src);
int copyLen = srcLen > trgLen ? trgLen : srcLen; // trgLen can either expand or shrink
CopyTo(src, 0, trg, 0, copyLen);
return trg;
}
public static final Object ResizeAddAry(Object src, Object... add) {
int srcLen = Len(src);
int addLen = add == null ? 0 : add.length;
int trgLen = srcLen + addLen;
Object trg = Create(ComponentType(src), trgLen);
CopyTo(src, 0, trg, 0, srcLen);
for (int i = 0; i < addLen; i++) {
SetAt(trg, i + srcLen, add[i]);
}
return trg;
}
}

View File

@@ -13,17 +13,12 @@ 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.objects.arrays;
import gplx.objects.errs.ErrUtl;
import gplx.objects.lists.ComparerAble;
import gplx.objects.lists.ComparerAbleSorter;
package gplx.types.basics.utls;
import gplx.types.errs.ErrUtl;
import gplx.types.commons.lists.ComparerAble;
import gplx.types.commons.lists.ComparerAbleSorter;
import java.lang.reflect.Array;
public class ArrayUtl {
public static int Len(Object ary) {return Array.getLength(ary);}
public static int LenObjAry(Object[] ary) {return ary == null ? 0 : ary.length;}
public static Object GetAt(Object ary, int i) {return Array.get(ary, i);}
public static void SetAt(Object ary, int i, Object o) {Array.set(ary, i, o);}
public static Object Create(Class<?> t, int count) {return Array.newInstance(t, count);}
public class ArrayUtl extends ArrayLni {
public static Object Expand(Object src, Object trg, int srcLen) {
try {System.arraycopy(src, 0, trg, 0, srcLen);}
catch (Exception e) {throw ErrUtl.NewFmt(e, "ArrayUtl.Expand failed; srcLen={0}", srcLen);}
@@ -31,7 +26,6 @@ public class ArrayUtl {
}
public static void Copy(Object src, Object trg) {System.arraycopy(src, 0, trg, 0, Len(src));}
public static void CopyTo(Object src, Object trg, int trgPos) {System.arraycopy(src, 0, trg, trgPos, Len(src));}
public static void CopyTo(Object src, int srcBgn, Object trg, int trgBgn, int srcLen) {System.arraycopy(src, srcBgn, trg, trgBgn, srcLen);}
public static Object Clone(Object src) {return Clone(src, 0, Len(src));}
public static Object Clone(Object src, int srcBgn) {return Clone(src, srcBgn, Array.getLength(src));}
private static Object Clone(Object src, int srcBgn, int srcEnd) {
@@ -40,13 +34,6 @@ public class ArrayUtl {
CopyTo(src, srcBgn, trg, 0, trgLen);
return trg;
}
public static Object Resize(Object src, int trgLen) {
Object trg = Create(ComponentType(src), trgLen);
int srcLen = Array.getLength(src);
int copyLen = srcLen > trgLen ? trgLen : srcLen; // trgLen can either expand or shrink
CopyTo(src, 0, trg, 0, copyLen);
return trg;
}
public static Object Append(Object src, Object add) {
int srcLen = Len(src);
int trgLen = srcLen + Len(add);
@@ -74,9 +61,4 @@ public class ArrayUtl {
}
public static void Sort(Object[] obj) {new ComparerAbleSorter().Sort(obj, obj.length);}
public static void Sort(Object[] obj, ComparerAble comparer) {new ComparerAbleSorter().Sort(obj, obj.length, true, comparer);}
public static Object Cast(Object o) {return o;} // NOTE: leftover from .NET; casts System.Object to System.Array
private static Class<?> ComponentType(Object ary) {
if (ary == null) throw ErrUtl.NewMsg("Array is null");
return ary.getClass().getComponentType();
}
}

View File

@@ -13,17 +13,13 @@ 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.objects.primitives;
import gplx.objects.ObjectUtl;
import gplx.objects.arrays.BryUtl;
import gplx.objects.errs.ErrUtl;
import gplx.objects.lists.CompareAbleUtl;
import gplx.objects.strings.AsciiByte;
import gplx.objects.strings.StringUtl;
package gplx.types.basics.utls;
import gplx.types.commons.lists.CompareAbleUtl;
import gplx.types.basics.constants.AsciiByte;
import gplx.types.errs.ErrUtl;
public class BoolUtl {
public static final String ClsValName = "bool";
public static final Class<?> ClsRefType = Boolean.class;
public static final boolean N = false , Y = true;
public static final byte NByte = 0 , YByte = 1 , NullByte = 127;
public static final int NInt = 0 , YInt = 1 , NullInt = -1;
@@ -33,15 +29,8 @@ public class BoolUtl {
public static boolean ByInt(int v) {return v == YInt;}
public static int ToInt(boolean v) {return v ? YInt : NInt;}
public static byte ToByte(boolean v) {return v ? YByte : NByte;}
public static String ToStrLower(boolean v) {return v ? TrueStr : FalseStr;}
public static boolean Cast(Object o) {
try {
return (Boolean)o;
}
catch (Exception e) {
throw ErrUtl.NewFmt(e, "failed to cast to boolean; obj={0}", ObjectUtl.ToStr(o));
}
}
public static String ToStrLower(boolean v) {return v ? TrueStr : FalseStr;}
public static boolean Cast(Object o) {try {return (Boolean)o;} catch (Exception e) {throw ErrUtl.NewCast(boolean.class, o);}}
public static boolean Parse(String raw) {
if ( StringUtl.Eq(raw, TrueStr)
|| StringUtl.Eq(raw, "True") // needed for Store_Wtr(){boolVal.toString();}

View File

@@ -0,0 +1,101 @@
package gplx.types.basics.utls;
public class BryLni {
public static final byte[] Empty = new byte[0];
public static final int LenSafe(byte[] v) {return v == null ? 0 : v.length;}
public static final boolean Eq(byte[] lhs, byte[] rhs) {return Eq(lhs, 0, LenSafe(lhs), rhs, 0, LenSafe(rhs));}
public static final boolean Eq(byte[] lhs, int lhsBgn, byte[] rhs) {return Eq(lhs, lhsBgn, LenSafe(lhs), rhs, 0, LenSafe(rhs));}
public static final boolean Eq(byte[] lhs, int lhsBgn, int lhsEnd, byte[] rhs) {return Eq(lhs, lhsBgn, lhsEnd, rhs, 0, LenSafe(rhs));}
public static final boolean Eq(byte[] lhs, int lhsBgn, int lhsEnd, byte[] rhs, int rhsBgn, int rhsEnd) {
if (lhsBgn == -1) return false;
int lhsLen = LenSafe(lhs);
if (lhsEnd > lhsLen) lhsEnd = lhsLen; // must limit lhsEnd to lhsLen, else ArrayIndexOutOfBounds below; DATE:2015-01-31
int rhsLen = rhsEnd - rhsBgn;
if (rhsLen != lhsEnd - lhsBgn) return false;
if (rhsLen == 0) return lhsEnd - lhsBgn == 0; // "" only matches ""
for (int i = 0; i < rhsLen; i++) {
int lhsPos = lhsBgn + i;
if (lhsPos >= lhsEnd) return false; // ran out of lhs; exit; EX: lhs=ab; rhs=abc
if (lhs[lhsPos] != rhs[i + rhsBgn]) return false;
}
return true;
}
public static final byte[] NewA7(String str) {
if (str == null) return null;
int strLen = str.length(); // PERF:NATIVE
if (strLen == 0) return Empty;
byte[] rv = new byte[strLen];
for (int i = 0; i < strLen; ++i) {
char c = str.charAt(i); // PERF:NATIVE
if (c > 128) c = '?';
rv[i] = (byte)c;
}
return rv;
}
public static int NewU8ByLen(String src, int srcLen) {
int rv = 0;
for (int i = 0; i < srcLen; ++i) {
char c = src.charAt(i);
int cLen = 0;
if ( c < 128) cLen = 1; // 1 << 7
else if ( c < 2048) cLen = 2; // 1 << 11
else if ( (c > 55295) // 0xD800
&& (c < 56320)) cLen = 4; // 0xDFFF
else cLen = 3; // 1 << 16
if (cLen == 4) ++i; // surrogate is 2 wide, not 1
rv += cLen;
}
return rv;
}
public static void NewU8Write(String src, int srcLen, byte[] trg, int trgPos) {
for (int i = 0; i < srcLen; ++i) {
char c = src.charAt(i);
if ( c < 128) {
trg[trgPos++] = (byte)c;
}
else if ( c < 2048) {
trg[trgPos++] = (byte)(0xC0 | (c >> 6));
trg[trgPos++] = (byte)(0x80 | (c & 0x3F));
}
else if ( (c > 55295) // 0xD800
&& (c < 56320)) { // 0xDFFF
if (i >= srcLen) throw ErrLni.NewMsg("incomplete surrogate pair at end of String");
char nxtChar = src.charAt(i + 1);
int v = 0x10000 + (c - 0xD800) * 0x400 + (nxtChar - 0xDC00);
trg[trgPos++] = (byte)(0xF0 | (v >> 18));
trg[trgPos++] = (byte)(0x80 | (v >> 12) & 0x3F);
trg[trgPos++] = (byte)(0x80 | (v >> 6) & 0x3F);
trg[trgPos++] = (byte)(0x80 | (v & 0x3F));
++i;
}
else {
trg[trgPos++] = (byte)(0xE0 | (c >> 12));
trg[trgPos++] = (byte)(0x80 | (c >> 6) & 0x3F);
trg[trgPos++] = (byte)(0x80 | (c & 0x3F));
}
}
}
public static void CopyTo(byte[] src, int srcBgn, int srcEnd, byte[] trg, int trgBgn) {
int trgAdj = trgBgn - srcBgn;
for (int i = srcBgn; i < srcEnd; i++)
trg[i + trgAdj] = src[i];
}
public static byte[] Resize(byte[] src, int trgLen) {return Resize(src, 0, trgLen);}
public static byte[] Resize(byte[] src, int srcBgn, int trgLen) {
byte[] trg = new byte[trgLen];
int srcLen = src.length;
if (srcLen > trgLen) srcLen = trgLen; // trgLen can be less than srcLen
CopyTo(src, srcBgn, srcLen, trg, 0);
return trg;
}
public static byte[] Mid(byte[] src, int bgn) {return Mid(src, bgn, src.length);}
public static byte[] Mid(byte[] src, int bgn, int end) {
try {
int len = end - bgn; if (len == 0) return BryLni.Empty;
byte[] rv = new byte[len];
for (int i = bgn; i < end; i++)
rv[i - bgn] = src[i];
return rv;
} catch (Exception e) {throw ErrLni.NewMsg("mid failed; " + " bgn=" + bgn + " end=" + end);}
}
}

View File

@@ -0,0 +1,752 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.utls;
import gplx.types.custom.brys.BryFind;
import gplx.types.commons.GfoDecimal;
import gplx.types.commons.GfoDecimalUtl;
import gplx.types.errs.ErrUtl;
import gplx.types.commons.lists.CompareAbleUtl;
import gplx.types.basics.constants.AsciiByte;
public class BryUtl extends BryLni {
public static final Class<?> ClsRefType = byte[].class;
public static final String ClsValName = "byte[]";
public static final byte[][] AryEmpty = new byte[0][];
public static final byte[] TrimAryWs = Mask(256, AsciiByte.Tab, AsciiByte.Nl, AsciiByte.Cr, AsciiByte.Space);
public static final byte DlmFld = (byte)'|';
public static final byte DlmRow = (byte)'\n';
public static final byte DlmQuote = (byte)'"';
public static final byte AsciiZero = 48;
public static final String FmtCsvDte = "yyyyMMdd HHmmss.fff";
public static byte ByteNegSign = (byte)'-';
public static int Len(byte[] v) {return v == null ? 0 : v.length;}
public static boolean IsNotNullOrEmpty(byte[] v) {return v != null && v.length > 0;}
public static boolean IsNullOrEmpty(byte[] v) {return v == null || v.length == 0;}
public static boolean HasAtEnd(byte[] src, byte[] lkp, int src_bgn, int src_end) {
int lkp_len = lkp.length;
if (src_bgn < 0) return false;
int pos = src_end - lkp_len; if (pos < src_bgn) return false; // lkp is longer than src
for (int i = 0; i < lkp_len; i++) {
if (lkp[i] != src[i + pos]) return false;
}
return true;
}
public static void Set(byte[] src, int bgn, int end, byte[] repl) {
int repl_len = repl.length;
for (int i = 0; i < repl_len; i++)
src[i + bgn] = repl[i];
}
public static void CopyToReversed(byte[] src, int src_bgn, int src_end, byte[] trg, int trg_bgn) {
// copies src to trg, but in reverse order; EX: trg="1" src="432." -> "1.234"
int len = src_end - src_bgn;
for (int i = 0; i < len; i++)
trg[trg_bgn + i] = src[src_end - i - 1];
}
public static boolean HasAtBgn(byte[] src, byte lkp) {return BryUtl.HasAtBgn(src, lkp, 0);}
public static boolean HasAtBgn(byte[] src, byte lkp, int src_bgn) {return src_bgn < src.length ? src[src_bgn] == lkp : false;}
public static boolean HasAtBgn(byte[] src, byte[] lkp) {return BryUtl.HasAtBgn(src, lkp, 0, src.length);}
public static boolean HasAtBgn(byte[] src, byte[] lkp, int src_bgn, int src_end) {
int lkp_len = lkp.length;
if (lkp_len + src_bgn > src_end) return false; // lkp is longer than src
for (int i = 0; i < lkp_len; i++) {
if (lkp[i] != src[i + src_bgn]) return false;
}
return true;
}
public static boolean HasAtEnd(byte[] src, byte lkp) {
if (src == null) return false;
int src_len = src.length;
if (src_len == 0) return false;
return src[src_len - 1] == lkp;
}
public static boolean HasAtEnd(byte[] src, byte[] lkp) {
int src_len = src.length;
return HasAtEnd(src, lkp, src_len - lkp.length, src_len);
}
public static byte[] Copy(byte[] src) {
int src_len = src.length;
byte[] trg = new byte[src_len];
for (int i = 0; i < src_len; ++i)
trg[i] = src[i];
return trg;
}
public static byte[] RepeatSpace(int len) {return BryUtl.Repeat(AsciiByte.Space, len);}
public static byte[] Repeat(byte b, int len) {
byte[] rv = new byte[len];
for (int i = 0; i < len; i++)
rv[i] = b;
return rv;
}
public static byte[] RepeatBry(byte[] bry, int len) {
int bry_len = bry.length;
int rv_len = len * bry_len;
byte[] rv = new byte[rv_len];
for (int i = 0; i < len; i++) {
for (int j = 0; j < bry_len; j++) {
rv[(i * bry_len) + j] = bry[j];
}
}
return rv;
}
public static byte[] Add(byte[] src, byte b) {
int src_len = src.length;
byte[] rv = new byte[src_len + 1];
CopyTo(src, 0, src_len, rv, 0);
rv[src_len] = b;
return rv;
}
public static byte[] Add(byte b, byte[] src) {
int src_len = src.length;
byte[] rv = new byte[src_len + 1];
CopyTo(src, 0, src_len, rv, 1);
rv[0] = b;
return rv;
}
public static byte[] Add(byte[]... all) {
int all_len = all.length, rv_len = 0;
for (int i = 0; i < all_len; ++i) {
byte[] cur = all[i]; if (cur == null) continue;
rv_len += cur.length;
}
byte[] rv = new byte[rv_len];
int rv_idx = 0;
for (int i = 0; i < all_len; ++i) {
byte[] cur = all[i]; if (cur == null) continue;
int cur_len = cur.length;
for (int j = 0; j < cur_len; ++j)
rv[rv_idx++] = cur[j];
}
return rv;
}
public static byte[] AddWithDlm(byte[] dlm, byte[]... ary) {
int ary_len = ary.length;
if (ary_len == 0) return BryUtl.Empty;
int dlm_len = dlm.length;
int rv_len = dlm_len * (ary_len - 1); // rv will have at least as many dlms as itms - 1
for (int i = 0; i < ary_len; i++) {
byte[] itm = ary[i];
if (itm != null) rv_len += itm.length;
}
int rv_pos = 0;
byte[] rv = new byte[rv_len];
for (int i = 0; i < ary_len; i++) {
byte[] itm = ary[i];
if (i != 0) {
for (int j = 0; j < dlm_len; j++) {
rv[rv_pos++] = dlm[j];
}
}
if (itm == null) continue;
int itm_len = itm.length;
for (int j = 0; j < itm_len; j++) {
rv[rv_pos++] = itm[j];
}
}
return rv;
}
public static byte[] AddWithDlm(byte dlm, byte[]... ary) {
int ary_len = ary.length;
if (ary_len == 0) return BryUtl.Empty;
int rv_len = ary_len - 1; // rv will have at least as many dlms as itms - 1
for (int i = 0; i < ary_len; i++) {
byte[] itm = ary[i];
if (itm != null) rv_len += itm.length;
}
int rv_pos = 0;
byte[] rv = new byte[rv_len];
for (int i = 0; i < ary_len; i++) {
byte[] itm = ary[i];
if (i != 0) rv[rv_pos++] = dlm;
if (itm == null) continue;
int itm_len = itm.length;
for (int j = 0; j < itm_len; j++) {
rv[rv_pos++] = itm[j];
}
}
return rv;
}
public static byte GetAtEnd(byte[] bry) {return bry[bry.length - 1];} // don't bother checking for errors; depend on error trace
public static boolean HasAt(byte[] src, int src_len, int pos, byte b) {return (pos < src_len) && (src[pos] == b);}
public static boolean Has(byte[] src, byte lkp) {
if (src == null) return false;
int len = src.length;
for (int i = 0; i < len; i++)
if (src[i] == lkp) return true;
return false;
}
public static void ReplaceAllDirect(byte[] src, byte find, byte repl) {BryUtl.ReplaceAllDirect(src, find, repl, 0, src.length);}
public static void ReplaceAllDirect(byte[] src, byte find, byte repl, int bgn, int end) {
for (int i = bgn; i < end; i++) {
byte b = src[i];
if (b == find) src[i] = repl;
}
}
public static byte[] TrimBgn(byte[] v, byte trim, int bgn) {
boolean trimmed = false;
int len = v.length;
int pos = bgn;
for (; pos < len; pos++) {
if (v[pos] == trim) {
trimmed = true;
}
else
break;
}
return trimmed ? BryLni.Mid(v, pos, len) : v;
}
public static byte[] TrimEnd(byte[] v, byte trim, int end) {
boolean trimmed = false;
int pos = end - 1; // NOTE: -1 b/c callers will always be passing pos + 1; EX: src, src_len
for (; pos > -1; pos--) {
if (v[pos] == trim) {
trimmed = true;
}
else
break;
}
return trimmed ? BryLni.Mid(v, 0, pos + 1) : v;
}
public static int Compare(byte[] lhs, byte[] rhs) {
if (lhs == null) return CompareAbleUtl.More;
else if (rhs == null) return CompareAbleUtl.Less;
else return BryUtl.Compare(lhs, 0, lhs.length, rhs, 0, rhs.length);
}
public static int Compare(byte[] lhs, int lhs_bgn, int lhs_end, byte[] rhs, int rhs_bgn, int rhs_end) {
int lhs_len = lhs_end - lhs_bgn, rhs_len = rhs_end - rhs_bgn;
int min = lhs_len < rhs_len ? lhs_len : rhs_len;
int rv = CompareAbleUtl.Same;
for (int i = 0; i < min; i++) {
rv = (lhs[i + lhs_bgn] & 0xff) - (rhs[i + rhs_bgn] & 0xff); // PATCH.JAVA:need to convert to unsigned byte
if (rv != CompareAbleUtl.Same) return rv > CompareAbleUtl.Same ? CompareAbleUtl.More : CompareAbleUtl.Less; // NOTE: changed from if (rv != CompareAble_.Same) return rv; DATE:2013-04-25
}
return IntUtl.Compare(lhs_len, rhs_len); // lhs and rhs share same beginning bytes; return len comparisons
}
public static boolean EqCiA7(byte[] lhs, byte[] rhs, int rhs_bgn, int rhs_end) {
if (lhs == null && rhs == null) return true;
else if (lhs == null || rhs == null) return false;
int lhs_len = lhs.length;
int rhs_len = rhs_end - rhs_bgn;
if (lhs_len != rhs_len) return false;
for (int i = 0; i < lhs_len; i++) {
byte lhs_b = lhs[i]; if (lhs_b > 64 && lhs_b < 91) lhs_b += 32; // lowercase
byte rhs_b = rhs[i + rhs_bgn]; if (rhs_b > 64 && rhs_b < 91) rhs_b += 32; // lowercase
if (lhs_b != rhs_b) return false;
}
return true;
}
public static boolean MatchWithSwap(byte[] src, int src_bgn, int src_end, byte[] find, int find_bgn, int find_end, byte swap_src, byte swap_trg) {// same as above, but used by XOWA for ttl matches;
int src_len = src.length;
if (src_end > src_len) src_end = src_len; // must limit src_end to src_len, else ArrayIndexOutOfBounds below; DATE:2015-01-31
int find_len = find_end - find_bgn;
if (find_len != src_end - src_bgn) return false;
if (find_len == 0) return src_end - src_bgn == 0; // "" only matches ""
for (int i = 0; i < find_len; i++) {
int pos = src_bgn + i;
if (pos >= src_end) return false; // ran out of src; exit; EX: src=ab; find=abc
byte src_byte = src[pos]; if (src_byte == swap_src) src_byte = swap_trg;
byte trg_byte = find[i + find_bgn]; if (trg_byte == swap_src) trg_byte = swap_trg;
if (src_byte != trg_byte) return false;
}
return true;
}
public static byte[] Limit(byte[] src, int len) {
if (src == null) return null;
int src_len = src.length;
return len < src_len ? BryLni.Mid(src, 0, len) : src;
}
public static byte[] MidByLen(byte[] src, int bgn, int len) {return Mid(src, bgn, bgn + len);}
public static byte[] MidByLenSafe(byte[] src, int bgn, int len) {
int src_len = src.length;
if (bgn < 0) bgn = 0;
if (len + bgn > src_len) len = (src_len - bgn);
return Mid(src, bgn, bgn + len);
}
public static byte[] MidSafe(byte[] src, int bgn, int end) {
if (src == null) return null;
int src_len = src.length;
if (bgn < 0)
bgn = 0;
else if (bgn >= src_len)
bgn = src_len;
if (end < 0)
end = 0;
else if (end >= src_len)
end = src_len;
if (bgn > end)
bgn = end;
else if (end < bgn)
end = bgn;
return Mid(src, bgn, end);
}
public static byte[] MidWithTrim(byte[] src, int bgn, int end) {
int len = end - bgn; if (len == 0) return BryUtl.Empty;
int actl_bgn = bgn, actl_end = end;
// trim at bgn
boolean chars_seen = false;
for (int i = bgn; i < end; ++i) {
switch (src[i]) {
case AsciiByte.Space: case AsciiByte.Tab: case AsciiByte.Nl: case AsciiByte.Cr:
break;
default:
chars_seen = true;
actl_bgn = i;
i = end;
break;
}
}
if (!chars_seen) return BryUtl.Empty; // all ws
// trim at end
for (int i = end - 1; i >= actl_bgn; --i) {
switch (src[i]) {
case AsciiByte.Space: case AsciiByte.Tab: case AsciiByte.Nl: case AsciiByte.Cr:
break;
default:
actl_end = i + 1;
i = -1;
break;
}
}
// extract mid
len = actl_end - actl_bgn; if (len == 0) return BryUtl.Empty;
byte[] rv = new byte[len];
for (int i = actl_bgn; i < actl_end; ++i)
rv[i - actl_bgn] = src[i];
return rv;
}
public static byte[] Mask(int len, byte... itms) {
byte[] rv = new byte[len];
int itms_len = itms.length;
for (int i = 0; i < itms_len; i++) {
byte itm = itms[i];
rv[itm & 0xFF] = itm; // PATCH.JAVA:need to convert to unsigned byte
}
return rv;
}
public static byte[] Trim(byte[] src) {return BryUtl.Trim(src, 0, src.length, true, true, TrimAryWs, true);}
public static byte[] Trim(byte[] src, int bgn, int end) {return BryUtl.Trim(src, bgn, end, true, true, TrimAryWs, true);}
public static byte[] Trim(byte[] src, int bgn, int end, boolean trim_bgn, boolean trim_end, byte[] trim_ary, boolean reuse_bry_if_noop) {
int txt_bgn = bgn, txt_end = end;
boolean all_ws = true;
if (trim_bgn) {
for (int i = bgn; i < end; i++) {
byte b = src[i];
if (trim_ary[b & 0xFF] == AsciiByte.Null) {
txt_bgn = i;
i = end;
all_ws = false;
}
}
if (all_ws) return BryUtl.Empty;
}
if (trim_end) {
for (int i = end - 1; i > -1; i--) {
byte b = src[i];
if (trim_ary[b & 0xFF] == AsciiByte.Null) {
txt_end = i + 1;
i = -1;
all_ws = false;
}
}
if (all_ws) return BryUtl.Empty;
}
if ( reuse_bry_if_noop
&& bgn == 0 && end == src.length // Trim is called on entire bry, not subset
&& bgn == txt_bgn && end == txt_end // Trim hasn't trimmed anything
) {
return src;
}
else
return BryLni.Mid(src, txt_bgn, txt_end);
}
public static boolean MatchBwdAny(byte[] src, int src_end, int src_bgn, byte[] find) { // NOTE: utf8 doesn't matter (matching byte for byte)
int find_len = find.length;
for (int i = 0; i < find_len; i++) {
int src_pos = src_end - i;
int find_pos = find_len - i - 1;
if (src_pos < src_bgn) return false; // ran out of src; exit; EX: src=ab; find=abc
if (src[src_pos] != find[find_pos]) return false;
}
return true;
}
public static byte[][] Ary(byte[]... ary) {return ary;}
public static byte[][] Ary(String... ary) {
int aryLen = ary.length;
byte[][] rv = new byte[aryLen][];
for (int i = 0; i < aryLen; i++) {
String itm = ary[i];
rv[i] = itm == null ? null : BryUtl.NewU8(itm);
}
return rv;
}
public static byte[] Cast(Object val) {return (byte[])val;}
public static byte[] NewByByte(byte b) {return new byte[] {b};}
public static byte[] CoalesceToEmpty(byte[] v) {return v == null ? BryUtl.Empty : v;}
public static byte[] Coalesce(byte[] v, byte[] or) {return v == null ? or : v;}
public static byte[] NewU8Safe(String str) {return str == null ? null : BryUtl.NewU8(str);}
public static byte[] NewU8(String src) {
try {
int srcLen = src.length();
if (srcLen == 0) return BryUtl.Empty;
int bryLen = NewU8ByLen(src, srcLen);
byte[] bry = new byte[bryLen];
NewU8Write(src, srcLen, bry, 0);
return bry;
}
catch (Exception e) {throw ErrUtl.NewFmt(e, "invalid UTF-8 sequence; src={0}", src);}
}
public static byte[][] AryObj(Object... ary) {
if (ary == null) return BryUtl.AryEmpty;
int ary_len = ary.length;
byte[][] rv = new byte[ary_len][];
for (int i = 0; i < ary_len; i++) {
Object itm = ary[i];
rv[i] = itm == null ? null : BryUtl.NewU8(ObjectUtl.ToStrOrEmpty(itm));
}
return rv;
}
public static boolean AryEq(byte[][] lhs, byte[][] rhs) {
int lhs_len = lhs.length;
int rhs_len = rhs.length;
if (lhs_len != rhs_len) return false;
for (int i = 0; i < lhs_len; ++i)
if (!BryLni.Eq(lhs[i], rhs[i])) return false;
return true;
}
public static byte[] IncrementLast(byte[] ary) {return BryUtl.IncrementLast(ary, ary.length - 1);}
public static byte[] IncrementLast(byte[] ary, int end_idx) {
for (int i = end_idx; i > -1; i--) {
byte end_val_old = ary[i];
byte end_val_new = (byte)(end_val_old + 1);
ary[i] = end_val_new;
if (end_val_new > (end_val_old & 0xff)) break; // PATCH.JAVA:need to convert to unsigned byte
}
return ary;
}
public static byte[] UcaseAll(byte[] src) {return BryUtl.XcaseAll(BoolUtl.Y, src, 0, -1);}
public static byte[] LcaseAll(byte[] src) {return BryUtl.XcaseAll(BoolUtl.N, src, 0, -1);}
public static byte[] LcaseAll(byte[] src, int bgn, int end) {return BryUtl.XcaseAll(BoolUtl.N, src, bgn, end);}
private static byte[] XcaseAll(boolean upper, byte[] src, int bgn, int end) {
if (src == null) return null;
int len = end == -1 ? src.length : end - bgn; if (len == 0) return src;
byte[] rv = new byte[len];
for (int i = 0; i < len; ++i) {
byte b = src[i + bgn];
if (upper) {
if (b > 96 && b < 123) b -= 32;
}
else {
if (b > 64 && b < 91) b += 32;
}
rv[i] = b;
}
return rv;
}
public static byte[] Ucase1st(byte[] src) {return BryUtl.Xcase1st(BoolUtl.Y, src);}
public static byte[] Lcase1st(byte[] src) {return BryUtl.Xcase1st(BoolUtl.N, src);}
private static byte[] Xcase1st(boolean upper, byte[] src) {
if (src == null) return null;
int len = src.length; if (len == 0) return src;
byte[] rv = new byte[len];
byte b = src[0];
if (upper) {
if (b > 96 && b < 123) b -= 32;
}
else {
if (b > 64 && b < 91) b += 32;
}
rv[0] = b;
for (int i = 1; i < len; ++i) {
rv[i] = src[i];
}
return rv;
}
public static byte[] ReplaceCreate(byte[] src, byte find, byte replace) {
byte[] rv = BryUtl.Copy(src);
BryUtl.ReplaceReuse(rv, find, replace);
return rv;
}
public static void ReplaceReuse(byte[] src, byte find, byte replace) {
int src_len = src.length;
for (int i = 0; i < src_len; i++) {
if (src[i] == find) src[i] = replace;
}
}
public static byte[] Replace(byte[] src, byte find, byte replace) {return BryUtl.Replace(src, 0, src.length, find, replace);}
public static byte[] Replace(byte[] src, int bgn, int end, byte find, byte replace) {
int src_len = src.length;
byte[] rv = new byte[src_len];
for (int i = bgn; i < end; ++i) {
byte b = src[i];
rv[i] = b == find ? replace : b;
}
for (int i = end; i < src_len; ++i)
rv[i] = src[i];
return rv;
}
public static byte[] NewByInts(int... ary) {
int len = ary.length;
byte[] rv = new byte[len];
for (int i = 0; i < len; i++)
rv[i] = (byte)ary[i];
return rv;
}
public static int ToIntByA7(byte[] v) {
int v_len = v.length;
int mod = 8 * (v_len - 1);
int rv = 0;
for (int i = 0; i < v_len; i++) {
rv |= v[i] << mod;
mod -= 8;
}
return rv;
// return ((0xFF & v[0]) << 24)
// | ((0xFF & v[1]) << 16)
// | ((0xFF & v[2]) << 8)
// | (0xFF & v[3]);
}
public static byte[] NewByInt(int v) {
byte b0 = (byte)(v >> 24);
byte b1 = (byte)(v >> 16);
byte b2 = (byte)(v >> 8);
byte b3 = (byte)(v);
if (b0 != 0) return new byte[] {b0, b1, b2, b3};
else if (b1 != 0) return new byte[] {b1, b2, b3};
else if (b2 != 0) return new byte[] {b2, b3};
else return new byte[] {b3};
}
public static boolean ToBoolOr(byte[] raw, boolean or) {
return BryLni.Eq(raw, BoolUtl.TrueBry) ? true : or;
}
public static boolean ToBoolByInt(byte[] ary) {
int rv = BryUtl.ToIntOr(ary, 0, ary.length, IntUtl.MinValue, BoolUtl.Y, null);
switch (rv) {
case 0: return false;
case 1: return true;
default: throw ErrUtl.NewArgs("could not parse to boolean int", "val", StringUtl.NewU8(ary));
}
}
public static int ToInt(byte[] ary) {return BryUtl.ToIntOrFail(ary, 0, ary.length);}
public static int ToIntOrFail(byte[] ary, int bgn, int end) {
int rv = BryUtl.ToIntOr(ary, bgn, end, IntUtl.MinValue, BoolUtl.Y, null);
if (rv == IntUtl.MinValue) throw ErrUtl.NewArgs("could not parse to int", "val", StringUtl.NewU8(ary, bgn, end));
return rv;
}
public static int ToIntOrNeg1(byte[] ary) {return BryUtl.ToIntOr(ary, 0 , ary.length, -1, BoolUtl.Y, null);}
public static int ToIntOr(byte[] ary, int or) {return BryUtl.ToIntOr(ary, 0 , ary.length, or, BoolUtl.Y, null);}
public static int ToIntOr(byte[] ary, int bgn, int end, int or) {return BryUtl.ToIntOr(ary, bgn , end , or, BoolUtl.Y, null);}
public static int ToIntOrStrict(byte[] ary, int or) {return BryUtl.ToIntOr(ary, 0 , ary.length, or, BoolUtl.N, null);}
private static int ToIntOr(byte[] ary, int bgn, int end, int or, boolean sign_is_valid, byte[] ignore_ary) {
if ( ary == null
|| end == bgn // null-len
) return or;
int rv = 0, multiple = 1;
for (int i = end - 1; i >= bgn; i--) { // -1 b/c end will always be next char; EX: {{{1}}}; bgn = 3, end = 4
byte b = ary[i];
switch (b) {
case AsciiByte.Num0: case AsciiByte.Num1: case AsciiByte.Num2: case AsciiByte.Num3: case AsciiByte.Num4:
case AsciiByte.Num5: case AsciiByte.Num6: case AsciiByte.Num7: case AsciiByte.Num8: case AsciiByte.Num9:
rv += multiple * (b - AsciiByte.Num0);
multiple *= 10;
break;
case AsciiByte.Dash:
return i == bgn && sign_is_valid ? rv * -1 : or;
case AsciiByte.Plus:
return i == bgn && sign_is_valid ? rv : or;
default:
boolean invalid = true;
if (ignore_ary != null) {
int ignore_ary_len = ignore_ary.length;
for (int j = 0; j < ignore_ary_len; j++) {
if (b == ignore_ary[j]) {
invalid = false;
break;
}
}
}
if (invalid) return or;
break;
}
}
return rv;
}
public static int ToIntOrTrimWs(byte[] ary, int bgn, int end, int or) { // NOTE: same as To_int_or, except trims ws at bgn / end; DATE:2014-02-09
if (end == bgn) return or; // null len
int rv = 0, multiple = 1;
boolean numbers_seen = false, ws_seen = false;
for (int i = end - 1; i >= bgn; i--) { // -1 b/c end will always be next char; EX: {{{1}}}; bgn = 3, end = 4
byte b = ary[i];
switch (b) {
case AsciiByte.Num0: case AsciiByte.Num1: case AsciiByte.Num2: case AsciiByte.Num3: case AsciiByte.Num4:
case AsciiByte.Num5: case AsciiByte.Num6: case AsciiByte.Num7: case AsciiByte.Num8: case AsciiByte.Num9:
rv += multiple * (b - AsciiByte.Num0);
multiple *= 10;
if (ws_seen) // "number ws number" pattern; invalid ws in middle; see tests
return or;
numbers_seen = true;
break;
case AsciiByte.Dash:
return i == bgn ? rv * -1 : or;
case AsciiByte.Space: case AsciiByte.Tab: case AsciiByte.Nl: case AsciiByte.Cr:
if (numbers_seen)
ws_seen = true;
break;
default: return or;
}
}
return rv;
}
public static int ToIntOrLax(byte[] ary, int bgn, int end, int or) {
if (end == bgn) return or; // null-len
int end_num = end;
for (int i = bgn; i < end; i++) {
byte b = ary[i];
switch (b) {
case AsciiByte.Num0: case AsciiByte.Num1: case AsciiByte.Num2: case AsciiByte.Num3: case AsciiByte.Num4:
case AsciiByte.Num5: case AsciiByte.Num6: case AsciiByte.Num7: case AsciiByte.Num8: case AsciiByte.Num9:
break;
case AsciiByte.Dash:
if (i != bgn) {
end_num = i;
i = end;
}
break;
default:
end_num = i;
i = end;
break;
}
}
return BryUtl.ToIntOr(ary, bgn, end_num, or);
}
public static long ToLongOr(byte[] ary, long or) {return BryUtl.ToLongOr(ary, null, 0, ary.length, or);}
public static long ToLongOr(byte[] ary, byte[] ignore_ary, int bgn, int end, long or) {
if ( ary == null
|| end == bgn // null-len
) return or;
long rv = 0, multiple = 1;
for (int i = end - 1; i >= bgn; i--) { // -1 b/c end will always be next char; EX: {{{1}}}; bgn = 3, end = 4
byte b = ary[i];
switch (b) {
case AsciiByte.Num0: case AsciiByte.Num1: case AsciiByte.Num2: case AsciiByte.Num3: case AsciiByte.Num4:
case AsciiByte.Num5: case AsciiByte.Num6: case AsciiByte.Num7: case AsciiByte.Num8: case AsciiByte.Num9:
rv += multiple * (b - AsciiByte.Num0);
multiple *= 10;
break;
case AsciiByte.Dash:
return i == bgn ? rv * -1 : or;
case AsciiByte.Plus:
return i == bgn ? rv : or;
default:
boolean invalid = true;
if (ignore_ary != null) {
int ignore_ary_len = ignore_ary.length;
for (int j = 0; j < ignore_ary_len; j++) {
if (b == ignore_ary[j]) {
invalid = false;
break;
}
}
}
if (invalid) return or;
break;
}
}
return rv;
}
public static double ToDouble(byte[] ary, int bgn, int end) {return DoubleUtl.Parse(StringUtl.NewU8(ary, bgn, end));}
public static double ToDoubleOr(byte[] bry, double or) {return DoubleUtl.ParseOr(StringUtl.NewU8(bry, 0, bry.length), or);}
public static double ToDoubleOr(byte[] ary, int bgn, int end, double or) {return DoubleUtl.ParseOr(StringUtl.NewU8(ary, bgn, end), or);}
public static byte[][] AryAdd(byte[][] lhs, byte[][] rhs) {
int lhs_len = lhs.length, rhs_len = rhs.length;
if (lhs_len == 0) return rhs;
else if (rhs_len == 0) return lhs;
else {
byte[][] rv = new byte[lhs_len + rhs_len][];
for (int i = 0; i < lhs_len; i++)
rv[i] = lhs[i];
for (int i = 0; i < rhs_len; i++)
rv[i + lhs_len] = rhs[i];
return rv;
}
}
public static int TrimEndPos(byte[] src, int end) {
for (int i = end - 1; i > -1; i--) {
switch (src[i]) {
case AsciiByte.Tab: case AsciiByte.Nl: case AsciiByte.Cr: case AsciiByte.Space:
break;
default:
return i + 1;
}
}
return 0;
}
public static void Clear(byte[] bry) {
int len = bry.length;
for (int i = 0; i < len; ++i)
bry[i] = ByteUtl.Zero;
}
public static byte[] ToA7Bry(int val, int pad_len) {return BryUtl.ToA7Bry(val, null, 0, pad_len);}
public static byte[] ToA7Bry(int val, byte[] ary, int aryPos, int pad_len) {
int neg = 0;
if (val < 0) {
val *= -1;
neg = 1;
}
int digits = val == 0 ? 0 : MathUtl.Log10(val);
digits += 1; // digits = log + 1; EX: Log(1-9) = 0, Log(10-99) = 1
int ary_len = digits + neg, aryBgn = aryPos, pad = 0;
if (ary_len < pad_len) { // padding specified
pad = pad_len - ary_len;
ary_len = pad_len;
}
if (ary == null) ary = new byte[ary_len];
long factor = 1; // factor needs to be long to handle 1 billion (for which factor would be 10 billion)
for (int i = 0; i < digits; i++) // calc maxFactor
factor *= 10;
if (neg == 1) ary[0] = ByteNegSign;
for (int i = 0; i < pad; i++) // fill ary with pad
ary[i + aryBgn] = AsciiByte.ToA7Str(0);
aryBgn += pad; // advance aryBgn by pad
for (int i = neg; i < ary_len - pad; i++) {
int denominator = (int)(factor / 10); // cache denominator to check for divide by 0
int digit = denominator == 0 ? 0 : (int)((val % factor) / denominator);
ary[aryBgn + i] = AsciiByte.ToA7Str(digit);
factor /= 10;
}
return ary;
}
public static GfoDecimal ToDecimal(byte[] ary, int bgn, int end) {return GfoDecimalUtl.Parse(StringUtl.NewU8(ary, bgn, end));}
public static boolean Has(byte[] src, byte[] lkp) {return BryFind.FindFwd(src, lkp) != BryFind.NotFound;}
public static byte[] ReplaceOne(byte[] orig, byte[] find, byte[] repl) {
// find val
int orig_len = orig.length;
int find_pos = BryFind.Find(orig, find, 0, orig_len, true);
if (find_pos == BryFind.NotFound) return orig; // nothing found; exit
// do copy
int find_len = find.length, repl_len = repl.length;
int rv_len = orig_len + repl_len - find_len;
byte[] rv = new byte[rv_len];
CopyTo(orig, 0 , find_pos, rv, 0 ); // copy orig before repl
CopyTo(repl, 0 , repl_len, rv, find_pos ); // copy repl
CopyTo(orig, find_pos + find_len, orig_len, rv, find_pos + repl_len); // copy orig after repl
return rv;
}
}

View File

@@ -0,0 +1,60 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.utls;
import gplx.types.commons.lists.CompareAbleUtl;
import gplx.types.errs.ErrUtl;
public class ByteUtl {
public static final String ClsValName = "byte";
public static final Class<?> ClsRefType = Byte.class;
public static final byte Zero = 0, MinValue = Byte.MIN_VALUE, MaxValue127 = 127;
public static byte Cast(Object o) {try {return (Byte)o;} catch (Exception e) {throw ErrUtl.NewCast(byte.class, o);}}
public static byte ByInt(int v) {return v > 127 ? (byte)(v - 256) : (byte)v;} // PERF?: (byte)(v & 0xff)
public static int ToInt(byte v) {return v < 0 ? (int)v + 256 : v;}
public static String ToStr(byte v) {return new Byte(v).toString();}
public static byte[] ToBry(byte v) {return new byte[] {v};}
public static byte Parse(String raw) {return Byte.parseByte(raw);}
public static byte ParseOr(String raw, byte or) {
try {
return raw == null
? or
: ByteUtl.Parse(raw);
}
catch (Exception e) {return or;}
}
public static boolean EqAny(byte v, byte... ary) {
for (byte itm : ary)
if (v == itm) return true;
return false;
}
public static boolean EqAll(byte v, byte... ary) {
for (byte itm : ary)
if (v != itm) return false;
return true;
}
public static int Compare(byte lhs, byte rhs) {
if (lhs == rhs) return CompareAbleUtl.Same;
else if (lhs < rhs) return CompareAbleUtl.Less;
else return CompareAbleUtl.More;
}
public static byte[] AryByInts(int... ary) {
int ary_len = ary.length;
byte[] rv = new byte[ary_len];
for (int i = 0; i < ary_len; i++) {
rv[i] = ByteUtl.ByInt(ary[i]);
}
return rv;
}
}

View File

@@ -0,0 +1,73 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.utls;
import gplx.types.errs.ErrUtl;
public class CharUtl {
public static final String ClsValName = "char";
public static final Class<?> ClsRefType = Character.class;
public static final char Null = '\0';
public static final char NewLine = '\n';
public static boolean IsLetterEnglish(char c) {
switch (c) {
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j':
case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J':
case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': return true;
default: return false;
}
}
public static boolean IsLetterLowerEnglish(char c) {
switch (c) {
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j':
case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': return true;
default: return false;
}
}
public static boolean IsNumber(char c) {
switch (c) {
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return true;
default: return false;
}
}
public static boolean IsWhitespace(char c) {
switch (c) {
case ' ': case '\t': case '\n': case '\r': return true;
default: return false;
}
}
public static boolean In(char match, char... ary) {
for (char itm : ary)
if (itm == match) return true;
return false;
}
public static int ToDigitOr(char c, int or) {
switch (c) {
case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4;
case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9;
default: return or;
}
}
public static int ToInt(char c) {return (int)c;}
public static String ToStr(char[] ary, int pos, int length) {return new String(ary, pos, length);}
public static String ToStr(int b) {return CharUtl.ToStr((char)b);}
public static String ToStr(char c) {return String.valueOf(c);}
public static char ByInt(int i) {return (char)i;}
public static char Cast(Object o) {try {return (Character)o;} catch(Exception e) {throw ErrUtl.NewCast(char.class, o);}}
public static char Parse(String raw) {try {return raw.charAt(0);} catch(Exception exc) {throw ErrUtl.NewParse(char.class, raw);}}
}

View File

@@ -0,0 +1,21 @@
package gplx.types.basics.utls;
public class ClassLni {
public static final boolean IsArray(Class<?> t) {return t.isArray();}
public static final boolean IsAssignableFromByObj(Object o, Class<?> generic) {return o == null ? false : IsAssignableFrom(generic, o.getClass());}
public static final boolean IsAssignableFrom(Class<?> generic, Class<?> specific) {return generic.isAssignableFrom(specific);}
public static final Class<?> TypeByObj(Object o) {return o.getClass();}
public static final String NameByObj(Object obj) {return obj == null ? StringLni.NullMark : Name(TypeByObj(obj));}
public static final String Name(Class<?> type) {return type.getName();}
public static final String CanonicalNameByObj(Object o) {return CanonicalName(o.getClass());}
public static final String CanonicalName(Class<?> type) {return type.getCanonicalName();}
public static final String SimpleNameByObj(Object obj) {return obj == null ? StringLni.NullMark : TypeByObj(obj).getSimpleName();}
public static final boolean EqByObj(Class<?> lhsType, Object rhsObj) {
Class<?> rhsType = rhsObj == null ? null : TypeByObj(rhsObj);
return Eq(lhsType, rhsType);
}
public static final boolean Eq(Class<?> lhs, Class<?> rhs) {// NOTE: same as ObjectUtl.Eq
if (lhs == null && rhs == null) return true;
else if (lhs == null || rhs == null) return false;
else return lhs.equals(rhs);
}
}

View File

@@ -13,8 +13,6 @@ 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.objects.primitives;
public class CharUtl {
public static final String ClsValName = "char";
public static final Class<?> ClsRefType = Character.class;
package gplx.types.basics.utls;
public class ClassUtl extends ClassLni {
}

View File

@@ -13,11 +13,17 @@ 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.objects.primitives;
package gplx.types.basics.utls;
import gplx.types.commons.lists.CompareAbleUtl;
import gplx.types.errs.ErrUtl;
public class DoubleUtl {
public static final String ClsValName = "double";
public static final Class<?> ClsRefType = Double.class;
public static final double MinValue = Double.MIN_VALUE;
public static final double NaN = Double.NaN;
public static final double InfinityPos = Double.POSITIVE_INFINITY;
public static final byte[] NaNBry = BryUtl.NewA7("NaN");
public static final byte[] InfinityPosBry = BryUtl.NewA7("INF");
public static String ToStrByPrintF(double val) {
// call sprintf-like format; EX:"sprintf((s), "%.14g", (n));"
return TrimZeroes(String.format("%.14g", val));
@@ -108,4 +114,30 @@ public class DoubleUtl {
}
return valStr;
}
public static double Cast(Object o) {try {return (Double)o;} catch(Exception e) {throw ErrUtl.NewCast(double.class, o);}}
public static double Parse(String raw) {try {return Double.parseDouble(raw);} catch(Exception e) {throw ErrUtl.NewParse(double.class, raw);}}
public static double ParseOr(String raw, double v) {try {return Double.parseDouble(raw);} catch(Exception e) {return v;}}
public static double CastOrParse(Object v) {
try {String s = StringUtl.CastOrNull(v); return s == null ? DoubleUtl.Cast(v) : DoubleUtl.Parse(s);}
catch (Exception e) {throw ErrUtl.NewCast(double.class, v);}
}
public static boolean IsNaN(double v) {return Double.isNaN(v);}
public static String ToStr(double v) {
int vInt = (int)v;
return v - vInt == 0 ? IntUtl.ToStr(vInt) : Double.toString(v);
}
public static String ToStrLoose(double v) {
int vInt = (int)v;
return v == vInt
// convert to int, and call print String to eliminate any trailing decimal places
? IntUtl.ToStr(vInt)
// DATE:2014-07-29; calling ((float)v).toString is better at removing trailing 0s than String.format("%g", v). note that .net .toString() handles it better; EX:2449.600000000000d
// DATE:2020-08-12; calling ToStrByPrintF b/c better at removing trailing 0s; ISSUE#:697;
: DoubleUtl.ToStrByPrintF(v);
}
public static int Compare(double lhs, double rhs) {
if (lhs == rhs) return CompareAbleUtl.Same;
else if (lhs < rhs) return CompareAbleUtl.Less;
else return CompareAbleUtl.More;
}
}

View File

@@ -0,0 +1,40 @@
package gplx.types.basics.utls;
import gplx.types.errs.Err;
public class ErrLni {
public static Err NewMsg(String msg) {return new Err("GENERAL", msg);}
public static final String Message(Throwable e) {
return Error.class.isAssignableFrom(e.getClass())
? e.toString() // NOTE: java.lang.Error returns null for "getMessage()"; return "toString()" instead
: e.getMessage();
}
public static final String Trace(Throwable e) {
StackTraceElement[] ary = e.getStackTrace();
String rv = "";
int len = ary.length;
for (int i = 0; i < len; i++) {
if (i != 0) rv += "\n";
rv += ary[i].toString();
}
return rv;
}
// private static String Trace_to_str(boolean is_gplx, boolean called_by_log, int ignore_lines, String trace) {
// if (trace == null) return ""; // WORKAROUND:.NET: StackTrace is only available when error is thrown; can't do "Console.Write(new Exception().StackTrace);
// String[] lines = StringUtl.SplitLang(trace, '\n'); int lines_len = lines.length;
// int line_bgn = 0;
// if (is_gplx) { // remove ErrUtl.NewArgs lines from trace for gplx exceptions
// for (int i = 0; i < lines_len; ++i) {
// String line = lines[i];
// if (StringUtl.HasAtBgn(line, "gplx.Err_.new")) continue; // ignore trace frames with "gplx.Err_.new"; EX: throw Err_.new_unimplemented
// line_bgn = i + ignore_lines;
// break;
// }
// }
// // concat lines
// String rv = "";
// String line_bgn_dlm = called_by_log ? "\t " : "\n "; // "\n " indents
// for (int i = line_bgn; i < lines_len; ++i)
// rv += line_bgn_dlm + lines[i];
// return rv;
// }
//
}

View File

@@ -0,0 +1,41 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.utls;
import gplx.types.commons.lists.CompareAbleUtl;
import gplx.types.errs.ErrUtl;
public class FloatUtl {
public static final String ClsValName = "float";
public static final Class<?> ClsRefType = Float.class;
public static final float NaN = Float.NaN;
public static boolean IsNaN(float v) {return Float.isNaN(v);}
public static float Cast(Object obj) {try {return (Float)obj;} catch(Exception exc) {throw ErrUtl.NewCast(float.class, obj);}}
public static float Parse(String raw) {try {return Float.parseFloat(raw);} catch(Exception exc) {throw ErrUtl.NewParse(float.class, raw);}}
public static int Compare(float lhs, float rhs) {
if ( lhs == rhs) return CompareAbleUtl.Same;
else if ( lhs < rhs) return CompareAbleUtl.Less;
else /*lhs > rhs*/ return CompareAbleUtl.More;
}
public static String ToStr(float v) {
int vAsInt = (int)v;
return v - vAsInt == 0 ? IntUtl.ToStr(vAsInt) : Float.toString(v);
}
public static float Div(int val, int divisor) {return (float)val / (float)divisor;}
public static float Div(long val, long divisor) {return (float)val / (float)divisor;}
public static int RoundUp(float val) {
int rv = (int)val;
return (rv == val) ? rv : rv + 1;
}
}

View File

@@ -0,0 +1,54 @@
package gplx.types.basics.utls;
public class IntLni {
public static final int
MinValue = Integer.MIN_VALUE,
MaxValue = Integer.MAX_VALUE,
MaxValue31 = 2147483647,
Neg1 = -1,
Null = MinValue,
Base1 = 1, // for base-1 lists / arrays; EX: PHP; [a, b, c]; [1] => a
Offset1 = 1, // common symbol for + 1 after current pos; EX: StringUtl.Mid(lhs + Offset1, rhs)
Zero = 0;
public static String ToStr(int v) {return new Integer(v).toString();}
public static boolean Between(int v, int lhs, int rhs) {
int lhsComp = v == lhs ? 0 : (v < lhs ? -1 : 1);
int rhsComp = v == rhs ? 0 : (v < rhs ? -1 : 1);
return (lhsComp * rhsComp) != 1; // 1 when v is (a) greater than both or (b) less than both
}
public static int ParseOr(String raw, int or) {
// process args
if (raw == null) return or;
int rawLen = StringUtl.Len(raw);
if (rawLen == 0) return or;
// loop backwards from nth to 0th char
int rv = 0, powerOf10 = 1;
for (int idx = rawLen - 1; idx >= 0; idx--) {
char cur = StringUtl.CharAt(raw, idx);
int digit = -1;
switch (cur) {
// numbers -> assign digit
case '0': digit = 0; break; case '1': digit = 1; break; case '2': digit = 2; break; case '3': digit = 3; break; case '4': digit = 4; break;
case '5': digit = 5; break; case '6': digit = 6; break; case '7': digit = 7; break; case '8': digit = 8; break; case '9': digit = 9; break;
// negative sign
case '-':
if (idx != 0) { // invalid if not 1st
return or;
}
else { // is first; multiply by -1
rv *= -1;
continue;
}
// anything else
default:
return or;
}
rv += (digit * powerOf10);
powerOf10 *= 10;
}
return rv;
}
}

View File

@@ -0,0 +1,176 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.utls;
import gplx.types.errs.ErrUtl;
import gplx.types.commons.lists.CompareAbleUtl;
import gplx.types.basics.constants.AsciiByte;
import gplx.types.basics.strings.bfrs.GfoStringBldr;
public class IntUtl extends IntLni {
public static final String ClsValName = "int";
public static final Class<?> ClsRefType = Integer.class;
public static int Cast(Object o) {
try {
return (Integer)o;
}
catch(Exception e) {
throw ErrUtl.NewFmt(e, "failed to cast to int; obj={0}", ObjectUtl.ToStr(o));
}
}
public static int CastOr(Object obj, int or) {try {return (Integer)obj;} catch(Exception e) {return or;}}
public static int CastOrParse(Object v) {
try {
String s = StringUtl.CastOrNull(v);
return s == null ? Cast(v) : IntUtl.Parse(s);
}
catch (Exception e) {throw ErrUtl.NewCast(int.class, v);}
}
public static int Parse(String raw) {try {return Integer.parseInt(raw);} catch(Exception e) {throw ErrUtl.NewParse(int.class, raw);}}
public static int ByHexBry(byte[] src) {return IntUtl.ByHexBry(src, 0, src.length);}
public static int ByHexBry(byte[] src, int bgn, int end) {
int rv = 0; int factor = 1;
for (int i = end - 1; i >= bgn; i--) {
int val = IntUtl.ByHexByte(src[i]);
rv += (val * factor);
factor *= 16;
}
return rv;
}
public static int ByHexByte(byte b) {
switch (b) {
case AsciiByte.Num0: case AsciiByte.Num1: case AsciiByte.Num2: case AsciiByte.Num3: case AsciiByte.Num4:
case AsciiByte.Num5: case AsciiByte.Num6: case AsciiByte.Num7: case AsciiByte.Num8: case AsciiByte.Num9:
return b - AsciiByte.Num0;
case AsciiByte.Ltr_A: case AsciiByte.Ltr_B: case AsciiByte.Ltr_C: case AsciiByte.Ltr_D: case AsciiByte.Ltr_E: case AsciiByte.Ltr_F:
return b - AsciiByte.Ltr_A + 10;
case AsciiByte.Ltr_a: case AsciiByte.Ltr_b: case AsciiByte.Ltr_c: case AsciiByte.Ltr_d: case AsciiByte.Ltr_e: case AsciiByte.Ltr_f:
return b - AsciiByte.Ltr_a + 10;
default:
return -1;
}
}
public static byte[] ToBry(int v) {return BryUtl.NewA7(ToStr(v));}
public static String ToStrFmt(int v, String fmt) {return new java.text.DecimalFormat(fmt).format(v);}
public static String ToStrPadBgnSpace(int val, int reqd_len) {return IntUtl.ToStrPad(val, reqd_len, BoolUtl.Y, AsciiByte.Space);} // EX: 1, 3 returns " 1"
public static String ToStrPadBgnZero(int val, int reqd_len) {return IntUtl.ToStrPad(val, reqd_len, BoolUtl.Y, AsciiByte.Num0);} // EX: 1, 3 returns "001"
private static String ToStrPad(int val, int reqd_len, boolean bgn, byte pad_chr) {
// get val_len and pad_len; exit early, if no padding needed
int val_len = CountDigits(val);
int pad_len = reqd_len - val_len;
if (pad_len < 0)
return ToStr(val);
// padding needed
GfoStringBldr bldr = new GfoStringBldr();
// handle negative numbers; EX: -1 -> "-001", not "00-1"
if (val < 0) {
bldr.AddChar('-');
val *= -1;
--val_len;
}
// build outpt
if (!bgn)
bldr.AddIntFixed(val, val_len);
bldr.AddCharRepeat((char)pad_chr, pad_len);
if (bgn)
bldr.AddIntFixed(val, val_len);
return bldr.ToStr();
}
public static String ToStrHex(int v) {return IntUtl.ToStrHex(BoolUtl.Y, BoolUtl.Y, v);}
public static String ToStrHex(boolean zero_pad, boolean upper, int v) {
String rv = Integer.toHexString(v);
int rvLen = StringUtl.Len(rv);
if (zero_pad && rvLen < 8) rv = StringUtl.Repeat("0", 8 - rvLen) + rv;
return upper ? StringUtl.Upper(rv) : rv;
}
public static int Compare(int lhs, int rhs) {
if (lhs == rhs) return CompareAbleUtl.Same;
else if (lhs < rhs) return CompareAbleUtl.Less;
else return CompareAbleUtl.More;
}
public static boolean In(int v, int comp0, int comp1) {return v == comp0 || v == comp1;}
public static boolean In(int v, int... ary) {
for (int itm : ary)
if (v == itm) return true;
return false;
}
public static int[] Log10Vals = new int[] {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, IntUtl.MaxValue};
public static int Log10ValsLen = 11;
public static int Log10(int v) {
if (v == 0) return 0;
int sign = 1;
if (v < 0) {
if (v == IntUtl.MinValue) return -9; // NOTE: IntUtl.MinValue * -1 = IntUtl.MinValue
v *= -1;
sign = -1;
}
int log10sLen = Log10Vals.length;
int rv = log10sLen - 2; // rv will only happen when v == IntUtl.MaxValue
int bgn = 0;
if (v > 1000) { // optimization to reduce number of ops to < 5
bgn = 3;
if (v > 1000000) bgn = 6;
}
for (int i = bgn; i < log10sLen; i++) {
if (v < Log10Vals[i]) {rv = i - 1; break;}
}
return rv * sign;
}
public static int CountDigits(int v) {
int log10 = Log10(v);
return v > -1 ? log10 + 1 : log10 * -1 + 2;
}
public static boolean RangeCheck(int v, int max) {return v >= 0 && v < max;}
public static void RangeCheckOrFailList(int v, int max, String s) {if (v < 0 || v >= max) throw ErrUtl.NewFmt("bounds check failed; msg={0} v={1} min={2} max={3}", s, v, 0, max - 1);}
public static boolean BoundsChk(int bgn, int end, int len) {return bgn > -1 && end < len;}
public static int BoundEnd(int v, int end) {return v >= end ? end - 1 : v;}
public static int Min(int lhs, int rhs) {return lhs < rhs ? lhs : rhs;}
public static int Max(int lhs, int rhs) {return lhs > rhs ? lhs : rhs;}
public static int MinMany(int... ary) {
int len = ary.length;
if (len == 0) throw ErrUtl.NewMsg("Min_many requires at least 1 value");
boolean init = true;
int min = MinValue;
for (int i = 0; i < len; ++i) {
int val = ary[i];
if (init) {
min = val;
init = false;
}
else {
if (val < min)
min = val;
}
}
return min;
}
public static int SubtractLong(long lhs, long rhs) {return (int)(lhs - rhs);}
public static int Div(int v, float divisor) {return (int)((float)v / divisor);}
public static int DivAndRoundUp(int v, int divisor) {
int whole = v / divisor;
int partial = v % divisor == 0 ? 0 : 1;
return whole + partial;
}
public static int Mult(int v, float multiplier) {
float product = ((float)v * multiplier); // WORKAROUND (DotNet): (int)((float)v * multiplier) returns 0 for 100 and .01f
return (int)product;
}
}

View File

@@ -0,0 +1,108 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.utls;
import gplx.types.commons.lists.CompareAbleUtl;
import gplx.types.errs.ErrUtl;
public class LongUtl {
public static final String ClsValName = "long";
public static final Class<?> ClsRefType = Long.class;
public static final int Log10AryLen = 21;
public static final long
MinValue = Long.MIN_VALUE;
public static final long MaxValue = Long.MAX_VALUE
;
public static long[] Log10Ary = new long[]
{ 1, 10, 100, 1000, 10000
, 100000, 1000000, 10000000, 100000000, 1000000000
, LongUtl.Pow(10, 10), LongUtl.Pow(10, 11), LongUtl.Pow(10, 12), LongUtl.Pow(10, 13), LongUtl.Pow(10, 14)
, LongUtl.Pow(10, 15), LongUtl.Pow(10, 16), LongUtl.Pow(10, 17), LongUtl.Pow(10, 18), LongUtl.Pow(10, 19)
, LongUtl.MaxValue
};
public static long Cast(Object obj) {try {return (Long)obj;} catch(Exception e) {throw ErrUtl.NewCast(long.class, obj);}}
public static String ToStr(long v) {return new Long(v).toString();}
public static long Parse(String raw) {try {return Long.parseLong(raw);} catch(Exception e) {throw ErrUtl.NewParse(long.class, raw);}}
public static String ToStrPadBgn(long v, int reqdPlaces) {return StringUtl.Pad(ToStr(v), reqdPlaces, "0", true);} // ex: 1, 3 returns 001
public static long ParseOr(String raw, long or) {
if (raw == null) return or;
try {
int rawLen = StringUtl.Len(raw);
if (raw == null || rawLen == 0) return or;
long rv = 0, factor = 1; int tmp = 0;
for (int i = rawLen; i > 0; i--) {
tmp = CharUtl.ToDigitOr(StringUtl.CharAt(raw, i - 1), IntUtl.MinValue);
if (tmp == IntUtl.MinValue) return or;
rv += (tmp * factor);
factor *= 10;
}
return rv;
} catch (Exception e) {return or;}
}
public static int Compare(long lhs, long rhs) {
if (lhs == rhs) return CompareAbleUtl.Same;
else if (lhs < rhs) return CompareAbleUtl.Less;
else return CompareAbleUtl.More;
}
private static int FindIdx(long[] ary, long find_val) {
int ary_len = ary.length;
int adj = 1;
int prv_pos = 0;
int prv_len = ary_len;
int cur_len = 0;
int cur_idx = 0;
long cur_val = 0;
while (true) {
cur_len = prv_len / 2;
if (prv_len % 2 == 1) ++cur_len;
cur_idx = prv_pos + (cur_len * adj);
if (cur_idx < 0) cur_idx = 0;
else if (cur_idx >= ary_len) cur_idx = ary_len - 1;
cur_val = ary[cur_idx];
if (find_val < cur_val) adj = -1;
else if (find_val > cur_val) adj = 1;
else if (find_val == cur_val) return cur_idx;
if (cur_len == 1) {
if (adj == -1 && cur_idx > 0)
return --cur_idx;
return cur_idx;
}
prv_len = cur_len;
prv_pos = cur_idx;
}
}
public static int DigitCount(long v) {
int adj = IntUtl.Base1;
if (v < 0) {
if (v == LongUtl.MinValue) return 19; // NOTE: LongUtl.Min_value * -1 = LongUtl.Min_value
v *= -1;
++adj;
}
return LongUtl.FindIdx(Log10Ary, v) + adj;
}
public static long Pow(int val, int exp) {
long rv = val;
for (int i = 1; i < exp; i++)
rv *= val;
return rv;
}
public static long IntMerge(int hi, int lo) {return (long)hi << 32 | (lo & 0xFFFFFFFFL);}
public static int IntSplitLo(long v) {return (int)(v);}
public static int IntSplitHi(long v) {return (int)(v >> 32);}
}
/* alternate for Int_merge; does not work in java
public static long MergeInts(int lo, int hi) {return (uint)(hi << 32) | (lo & 0xffffffff);}
public static int SplitLo(long v) {return (int)(((ulong)v & 0x00000000ffffffff));}
public static int SplitHi(long v) {return (int)(((ulong)v & 0xffffffff00000000)) >> 32;}
*/

View File

@@ -0,0 +1,69 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.utls;
public class MathUtl {
public static int Min(int val0, int val1) {return val0 < val1 ? val0 : val1;}
public static int Max(int val0, int val1) {return val0 > val1 ? val0 : val1;}
public static int Abs(int val) {return val > 0 ? val : val * -1;}
public static long Abs(long val) {return val > 0 ? val : val * -1;}
public static float Abs(float val) {return val > 0 ? val : val * -1;}
public static double AbsAsDouble(double val) {return val > 0 ? val : val * -1;}
public static int Trunc(double v) {return (int)v;}
public static double Round(double v, int places) {return java.math.BigDecimal.valueOf(v).setScale(places, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();}
public static double Ceil(double v) {return Math.ceil(v);}
public static int CeilAsInt(double v) {return (int)Ceil(v);}
public static double Floor(double v) {return Math.floor(v);}
public static int FloorAsInt(double v) {return (int)Floor(v);}
public static int DivSafeAsInt(int val, int divisor) {return divisor == 0 ? 0 : val / divisor;}
public static long DivSafeAsLong(long val, long divisor) {return divisor == 0 ? 0 : val / divisor;}
public static double DivSafeAsDouble(double val, double divisor) {return divisor == 0 ? 0 : val / divisor;}
public static double Pow(double val, double exponent) {return Math.pow(val, exponent);}
public static int PowAsInt(int val, int exponent) {return (int)Math.pow(val, exponent);}
public static double Exp(double v) {return Math.exp(v);}
public static double Sqrt(double v) {return Math.sqrt(v);}
public static double Log(double v) {return Math.log(v);}
public static int Log10(int val) {
if (val <= 0) return IntUtl.MinValue;
int rv = -1, baseVal = 10;
while (val != 0) {
val = (val / baseVal);
rv++;
}
return rv;
}
public static double Sin(double v) {return Math.sin(v);}
public static double Cos(double v) {return Math.cos(v);}
public static double Tan(double v) {return Math.tan(v);}
public static double Asin(double v) {return Math.asin(v);}
public static double Acos(double v) {return Math.acos(v);}
public static double Atan(double v) {return Math.atan(v);}
public static int[] Base2Ary(int v, int max) {
int[] idxs = new int[32];
int cur = v, mult = max, idx = 0;
while (mult > 0) {
int tmp = cur / mult;
if (tmp >= 1) {
idxs[idx++] = mult;
cur -= mult;
}
mult /= 2;
}
int[] rv = new int[idx];
for (int i = 0; i < idx; i++)
rv[i] = idxs[idx - i - 1];
return rv;
}
}

View File

@@ -0,0 +1,19 @@
package gplx.types.basics.utls;
public class ObjectLni {
public static final String ClsValName = "Object";
public static final Object[] AryEmpty = new Object[0];
public static final byte[] NullBry = BryLni.NewA7("null");
public static boolean Eq(Object lhs, Object rhs) {
if (lhs == null && rhs == null) return true;
else if (lhs == null || rhs == null) return false;
else return lhs.equals(rhs);
}
public static final String ToStrOrNullMark(Object v) {return v == null ? StringLni.NullMark : ToStr(v);}
public static final String ToStr(Object v) {
Class<?> c = v.getClass();
if (ClassLni.Eq(c, String.class)) return (String)v;
else if (ClassLni.Eq(c, byte[].class)) return StringLni.NewByBry((byte[])v);
else return v.toString();
}
}

View File

@@ -0,0 +1,43 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.utls;
public class ObjectUtl extends ObjectLni {
public static Object[] Ary(Object... ary) {return ary;}
public static Object[] AryAdd(Object[] lhs, Object[] rhs) {
int lhsLen = lhs.length, rhsLen = rhs.length;
if (lhsLen == 0) return rhs;
else if (rhsLen == 0) return lhs;
int rvLen = lhsLen + rhsLen;
Object[] rv = new Object[rvLen];
for (int i = 0; i < lhsLen; ++i)
rv[i] = lhs[i];
for (int i = lhsLen; i < rvLen; ++i)
rv[i] = rhs[i - lhsLen];
return rv;
}
public static String ToStrOr(Object v, String or) {return v == null ? or : ToStr(v);}
public static String ToStrOrNull(Object v) {return v == null ? null : ToStr(v);}
public static String ToStrOrEmpty(Object v) {return v == null ? StringUtl.Empty : ToStr(v);}
public static String ToStrLooseOr(Object v, String or) { // tries to pretty-print doubles; also standardizes true/false; DATE:2014-07-14
if (v == null) return null;
Class<?> c = ClassUtl.TypeByObj(v);
if (ClassUtl.Eq(c, StringUtl.ClsRefType)) return (String)v;
else if (ClassUtl.Eq(c, BryUtl.ClsRefType)) return StringUtl.NewU8((byte[])v);
else if (ClassUtl.Eq(c, BoolUtl.ClsRefType)) return BoolUtl.Cast(v) ? BoolUtl.TrueStr : BoolUtl.FalseStr; // always return "true" / "false"
else if (ClassUtl.Eq(c, DoubleUtl.ClsRefType)) return DoubleUtl.ToStrLoose(DoubleUtl.Cast(v));
else return v.toString();
}
}

View File

@@ -13,8 +13,10 @@ 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.objects.primitives;
package gplx.types.basics.utls;
import gplx.types.errs.ErrUtl;
public class ShortUtl {
public static final String ClsValName = "short";
public static final Class<?> ClsRefType = Short.class;
public static short Cast(Object obj) {try {return (Short)obj;} catch(Exception exc) {throw ErrUtl.NewCast(short.class, obj);}}
}

View File

@@ -0,0 +1,61 @@
package gplx.types.basics.utls;
import gplx.types.basics.strings.bfrs.StringBuilderLni;
public class StringFormatLni {
// use C# flavor ("a {0}") rather than Java format ("a %s"); also: (a) don't fail on format errors; (b) escape brackets by doubling
private static final char FormatItmLhs = '{', FormatItmRhs = '}';
public static String Format(String fmt, Object... args) {
// init vars
int argsLen = args.length;
if (argsLen == 0) return fmt; // nothing to format
int fmtLen = StringLni.Len(fmt);
// loop vars
int pos = 0; String argIdxStr = ""; boolean insideBrackets = false;
StringBuilderLni bfr = new StringBuilderLni();
while (pos < fmtLen) { // loop over every char; NOTE: UT8-SAFE b/c only checking for "{"; "}"
char c = StringLni.CharAt(fmt, pos);
if (insideBrackets) {
if (c == FormatItmLhs) { // first FormatItmLhs is fake; add FormatItmLhs and whatever is in argIdxStr
bfr.LniAddChar(FormatItmLhs);
bfr.LniAdd(argIdxStr);
argIdxStr = "";
}
else if (c == FormatItmRhs) { // itm completed
int argsIdx = IntLni.ParseOr(argIdxStr, IntLni.MinValue);
String itm = argsIdx != IntLni.MinValue && IntLni.Between(argsIdx, 0, argsLen - 1) // check (a) argsIdx is num; (b) argsIdx is in bounds
? ObjectLni.ToStrOrNullMark(args[argsIdx]) // valid; add itm
: FormatItmLhs + argIdxStr + FormatItmRhs; // not valid; just add String
bfr.LniAdd(itm);
insideBrackets = false;
argIdxStr = "";
}
else
argIdxStr += c;
}
else {
if (c == FormatItmLhs || c == FormatItmRhs) {
boolean posIsEnd = pos == fmtLen - 1;
if (posIsEnd) // last char is "{" or "}" (and not insideBrackets); ignore and just ad
bfr.LniAddChar(c);
else {
char next = StringLni.CharAt(fmt, pos + 1);
if (next == c) { // "{{" or "}}": escape by doubling
bfr.LniAddChar(c);
pos++;
}
else
insideBrackets = true;
}
}
else
bfr.LniAddChar(c);
}
pos++;
}
if (StringLni.Len(argIdxStr) > 0) { // unclosed bracket; add FormatItmLhs and whatever is in argIdxStr; ex: "{0"
bfr.LniAddChar(FormatItmLhs);
bfr.LniAdd(argIdxStr);
}
return bfr.ToStr();
}
}

View File

@@ -0,0 +1,64 @@
package gplx.types.basics.utls;
import java.util.Objects;
public class StringLni {
public static final Class<?> ClsRefType = String.class;
public static final String ClsValName = "string";
public static final int FindNone = -1;
public static final int PosNeg1 = -1;
public static final String
Empty = "",
Tab = "\t",
Nl = "\n",
CrLf = "\r\n",
NullMark = "<<NULL>>";
public static final String[] AryEmpty = new String[0];
public static final boolean Eq(String lhs, String rhs) {return Objects.equals(lhs, rhs);}
public static final boolean EqNot(String lhs, String rhs) {return !Objects.equals(lhs, rhs);}
public static final int Len(String s) {return s.length();}
public static final boolean IsNullOrEmpty(String s) {return s == null || s.length() == 0;}
public static final boolean IsNotNullOrEmpty(String s) {return s != null && s.length() > 0;}
public static final boolean Has(String s, String find) {return s.indexOf(find) != FindNone;}
public static final boolean HasAtBgn(String s, String v) {return s.startsWith(v);}
public static final boolean HasAtEnd(String s, String v) {return s.endsWith(v);}
public static final char CharAt(String s, int i) {return s.charAt(i);}
public static final int CodePointAt(String s, int i) {return s.codePointAt(i);}
public static final int FindFwd(String s, String find) {return s.indexOf(find);}
public static final int FindFwd(String s, String find, int pos) {return s.indexOf(find, pos);}
public static final int FindBwd(String s, String find) {return s.lastIndexOf(find);}
public static final int FindBwd(String s, String find, int pos) {return s.lastIndexOf(find, pos);}
public static final String Cast(Object v) {return (String)v;}
public static final String CastOrNull(Object obj) {return obj instanceof String ? (String)obj : null;}
public static final String Lower(String s) {return s.toLowerCase();}
public static final String Upper(String s) {return s.toUpperCase();}
public static final String CaseNormalize(boolean caseMatch, String s) {return caseMatch ? s : Lower(s);}
public static final String Trim(String s) {return s.trim();}
public static final String Mid(String s, int bgn) {return s.substring(bgn);}
public static final String MidByLen(String s, int bgn, int len) {return s.substring(bgn, bgn + len);}
public static final String Replace(String s, String find, String repl) {return s.replace(find, repl);}
public static final String NewByBry(byte[] v) {return v == null ? null : new String(v);}
public static final char[] ToCharAry(String s) {return s.toCharArray();}
public static final String NewA7(byte[] v) {return v == null ? null : NewA7(v, 0, v.length);}
public static final String NewA7(byte[] v, int bgn, int end) {
try {
return v == null
? null
: new String(v, bgn, end - bgn, "ASCII");
}
catch (Exception e) {throw ErrLni.NewMsg("unsupported encoding; bgn=" + bgn + " end=" + end);}
}
public static final String NewU8ByLen(byte[] v, int bgn, int len) {
int vLen = v.length;
if (bgn + len > vLen) len = vLen - bgn;
return NewU8(v, bgn, bgn + len);
}
public static final String NewU8(byte[] v) {return v == null ? null : NewU8(v, 0, v.length);}
public static final String NewU8(byte[] v, int bgn, int end) {
try {
return v == null
? null
: new String(v, bgn, end - bgn, "UTF-8");
}
catch (Exception e) {throw ErrLni.NewMsg("unsupported encoding; bgn=" + bgn + " end=" + end);}
}
}

View File

@@ -0,0 +1,329 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.utls;
import gplx.types.commons.lists.CompareAbleUtl;
import gplx.types.commons.lists.GfoListBase;
import gplx.types.basics.strings.bfrs.GfoStringBldr;
import gplx.types.errs.ErrUtl;
public class StringUtl extends StringLni {
public static boolean EqAny(String lhs, String... rhsAry) {
for (int i = 0; i < rhsAry.length; i++)
if (Eq(lhs, rhsAry[i])) return true;
return false;
}
public static boolean In(String s, String... ary) {
for (String itm : ary)
if (Eq(s, itm)) return true;
return false;
}
public static int Compare(String lhs, String rhs) {
int compare = lhs.compareTo(rhs); // NOTE: should this do null check?
// NOTE: need to do explicit comparison b/c String.compare returns magnitude of difference; "k".compareTo("a") == 10
if (compare == CompareAbleUtl.Same) return CompareAbleUtl.Same;
else if (compare < CompareAbleUtl.Same) return CompareAbleUtl.Less;
else /* (compare > CompareAbleUtl.Same) */ return CompareAbleUtl.More;
}
public static int CompareIgnoreCase(String lhs, String rhs) {
if (lhs == null && rhs != null) return CompareAbleUtl.Less;
else if (lhs != null && rhs == null) return CompareAbleUtl.More;
else if (lhs == null && rhs == null) return CompareAbleUtl.Same;
else return lhs.compareToIgnoreCase(rhs);
}
public static int Count(String s, String part) {
int count = 0, pos = -1; // -1 b/c first pass must be 0 (see pos + 1 below)
do {
pos = FindFwd(s, part, pos + 1);
if (pos == FindNone) break;
count++;
} while (true);
return count;
}
public static String LowerFirst(String s) {
int len = Len(s); if (len == 0) return Empty;
String char0 = Lower(MidByLen(s, 0, 1));
return len == 1 ? char0 : char0 + Mid(s, 1);
}
public static String UpperFirst(String s) {
int len = Len(s); if (len == 0) return Empty;
String char0 = Upper(MidByLen(s, 0, 1));
return len == 1 ? char0 : char0 + Mid(s, 1);
}
public static String Repeat(String s, int count) {
if (count < 0) throw ErrUtl.NewArgs("count cannot be negative", "count", count, "s", s);
GfoStringBldr sb = new GfoStringBldr();
for (int i = 0; i < count; i++)
sb.Add(s);
return sb.ToStr();
}
public static String PadBgn(String s, int totalLen, String pad) {return Pad(s, totalLen, pad, true);}
public static String PadEnd(String s, int totalLen, String pad) {return Pad(s, totalLen, pad, false);}
public static String Pad(String s, int totalLen, String pad, boolean bgn) {
int sLen = Len(s);
int padLen = totalLen - sLen; if (padLen < 0) return s;
GfoStringBldr sb = new GfoStringBldr();
if (!bgn) sb.Add(s);
for (int i = 0; i < padLen; i++)
sb.Add(pad);
if (bgn) sb.Add(s);
return sb.ToStr();
}
public static String Mid(String s, int bgn, int end) {
try {return MidByLen(s, bgn, end - bgn);}
catch (Exception e) {
int len = s == null ? 0 : Len(s);
String msg = "";
if (s == null) msg = "s is null";
else if (bgn > end) msg = "@bgn > @end";
else if (bgn < 0 || bgn >= len) msg = "@bgn is invalid";
else if (end < 0 || end > len) msg = "@end is invalid";
throw ErrUtl.NewArgs(msg, "s", s, "bgn", bgn, "end", end, "len", len);
}
}
public static String MidByLenSafe(String s, int bgn, int len) {
if (bgn + len >= Len(s)) len = Len(s) - bgn;
return MidByLen(s, bgn, len);
}
public static String GetStrBefore(String s, String spr) {
int sprPos = FindFwd(s, spr); if (sprPos == FindNone) throw ErrUtl.NewArgs("could not find spr", "s", s, "spr", spr);
return Mid(s, 0, sprPos);
}
public static String GetStrAfter(String s, String spr) {
int sprPos = FindFwd(s, spr); if (sprPos == FindNone) throw ErrUtl.NewArgs("could not find spr", "s", s, "spr", spr);
return Mid(s, sprPos + 1);
}
public static String ExtractAfterBwd(String src, String dlm) {
int dlm_pos = FindBwd(src, dlm); if (dlm_pos == FindNone) return Empty;
int src_len = Len(src); if (dlm_pos == src_len - 1) return Empty;
return Mid(src, dlm_pos + 1, src_len);
}
public static String LimitToFirst(String s, int len) {
if (len < 0) throw ErrUtl.NewFmt("len cannot be < 0; len={0}", len);
int sLen = Len(s); if (len > sLen) return s;
return MidByLen(s, 0, len);
}
public static String DelBgn(String s, int count) {
if (count < 0) throw ErrUtl.NewFmt("count cannot be < 0; count={0}", count);
if (s == null) throw ErrUtl.NewNull("s");
int len = Len(s); if (count > len) throw ErrUtl.NewArgs("count cannot be > @len", "count", count, "len", len);
return Mid(s, count);
}
public static String DelEnd(String s, int count) {
if (count < 0) throw ErrUtl.NewFmt("len cannot be < 0; len={0}", count);
if (s == null) throw ErrUtl.NewNull("s");
int len = Len(s); if (count > len) throw ErrUtl.NewArgs("count cannot be > len", "count", count, "len", len);
return MidByLen(s, 0, len + -count);
}
public static String DelEndIf(String s, String find) {
if (s == null) throw ErrUtl.NewNull("s");
if (find == null) throw ErrUtl.NewNull("find");
return HasAtEnd(s, find) ? MidByLen(s, 0, Len(s) - Len(find)) : s;
}
public static String Insert(String s, int pos, String toInsert) {
if (pos < 0 || pos >= Len(s)) throw ErrUtl.NewArgs("insert failed; pos invalid", "pos", pos, "s", s, "toInsert", toInsert);
return s.substring(0, pos) + toInsert + s.substring(pos);
}
public static String FormatOrEmptyStrIfNull(String fmt, Object arg) {return arg == null ? "" : Format(fmt, arg);}
public static String Format(String fmt, Object... args) {return StringFormatLni.Format(fmt, args);}
public static String Concat(char... ary) {return new String(ary);}
public static String Concat(String s1, String s2, String s3) {return s1 + s2 + s3;}
public static String Concat(String... ary) {
GfoStringBldr sb = new GfoStringBldr();
for (String val : ary)
sb.Add(val);
return sb.ToStr();
}
public static String ConcatObjs(Object... ary) {
GfoStringBldr sb = new GfoStringBldr();
for (Object val : ary)
sb.AddObj(val);
return sb.ToStr();
}
public static String ConcatWithObj(String spr, Object... ary) {
GfoStringBldr sb = new GfoStringBldr();
int len = ArrayUtl.Len(ary);
for (int i = 0; i < len; i++) {
if (i != 0) sb.Add(spr);
Object val = ary[i];
sb.AddObj(ObjectUtl.ToStrOrEmpty(val));
}
return sb.ToStr();
}
public static String ConcatWith(String spr, String... ary) {
GfoStringBldr sb = new GfoStringBldr();
int len = ary.length;
for (int i = 0; i < len; i++) {
if (i != 0) sb.Add(spr);
sb.Add(ary[i]);
}
return sb.ToStr();
}
public static String ConcatLinesNl(String... values) {
GfoStringBldr sb = new GfoStringBldr();
for (String val : values)
sb.Add(val).Add("\n");
return sb.ToStr();
}
public static String ConcatLinesNlSkipLast(String... ary) {
GfoStringBldr sb = new GfoStringBldr();
int ary_len = ary.length; int ary_end = ary_len - 1;
for (int i = 0; i < ary_len; i++) {
sb.Add(ary[i]);
if (i != ary_end) sb.Add("\n");
}
return sb.ToStr();
}
public static String ConcatLinesCrlf(String... values) {
GfoStringBldr sb = new GfoStringBldr();
for (String val : values)
sb.Add(val).Add(CrLf);
return sb.ToStr();
}
public static String ConcatLinesCrlfSkipLast(String... values) {
GfoStringBldr sb = new GfoStringBldr();
for (String val : values) {
if (sb.Len() != 0) sb.Add(CrLf);
sb.Add(val);
}
return sb.ToStr();
}
public static String[] Ary(String... ary) {return ary;}
public static String[] Ary(byte[]... ary) {
if (ary == null) return AryEmpty;
int ary_len = ary.length;
String[] rv = new String[ary_len];
for (int i = 0; i < ary_len; i++) {
byte[] itm = ary[i];
rv[i] = itm == null ? null : NewU8(itm);
}
return rv;
}
public static String[] AryWoNull(String... ary) {
GfoListBase<String> list = new GfoListBase<>();
int len = ary.length;
for (int i = 0; i < len; ++i) {
String itm = ary[i];
if (itm == null) continue;
list.Add(itm);
}
return list.ToAry(String.class);
}
public static String AryToStr(String... ary) {
GfoStringBldr sb = new GfoStringBldr();
for (String s : ary)
sb.Add(s).Add(";");
return sb.ToStr();
}
public static String[] AryAdd(String[]... arys) {
if (arys == null) return AryEmpty;
int arys_len = arys.length;
int rv_len = 0;
for (int i = 0; i < arys_len; i++) {
String[] ary = arys[i];
rv_len += ary.length;
}
int rv_idx = 0;
String[] rv = new String[rv_len];
for (int i = 0; i < arys_len; i++) {
String[] ary = arys[i];
int ary_len = ary.length;
for (int j = 0; j < ary_len; j++)
rv[rv_idx++] = ary[j];
}
return rv;
}
public static String[] AryFlatten(String[][] src_ary) {
int trg_len = 0;
int src_len = ArrayUtl.Len(src_ary);
for (int i = 0; i < src_len; i++) {
String[] itm = src_ary[i];
if (itm != null) trg_len += ArrayUtl.Len(itm);
}
String[] trg_ary = new String[trg_len];
trg_len = 0;
for (int i = 0; i < src_len; i++) {
String[] itm = src_ary[i];
if (itm == null) continue;
int itm_len = ArrayUtl.Len(itm);
for (int j = 0; j < itm_len; j++)
trg_ary[trg_len++] = itm[j];
}
return trg_ary;
}
public static String[] Split(String raw, char dlm) {return Split(raw, dlm, false);}
public static String[] Split(String raw, char dlm, boolean addEmptyIfDlmIsLast) {
GfoListBase<String> list = new GfoListBase<>();
GfoStringBldr sb = new GfoStringBldr();
int rawLen = Len(raw); char c = '\0';
for (int i = 0; i < rawLen; i++) {
c = CharAt(raw, i);
if (c == dlm) {
if (!addEmptyIfDlmIsLast && sb.Len() == 0 && i == rawLen - 1) {}
else list.Add(sb.ToStrAndClear());
}
else
sb.AddChar(c);
}
if (sb.Len() > 0)
list.Add(sb.ToStrAndClear());
return list.ToAry(String.class);
}
public static String[] Split(String s, String separator) {return SplitDo(s, separator, false);}
public static String[] SplitLinesNl(String s) {return Split(s, Nl);}
public static String[] SplitLinesCrLf(String s) {return Split(s, CrLf);}
public static String[] SplitLinesAny(String s) {return SplitDo(s, Nl, true);}
public static String[] SplitLang(String s, char c) {return s.split(Character.toString(c));}
private static String[] SplitDo(String raw, String spr, boolean skipChar13) {
if ( Eq(raw, "") // "".Split('a') return array with one member: ""
|| Eq(spr, "")) // "a".Split('\0') returns array with one member: "a"
return new String[] {raw};
GfoListBase<String> list = new GfoListBase<>();
GfoStringBldr sb = new GfoStringBldr();
int i = 0, sprPos = 0; boolean sprMatched = false; char spr0 = CharAt(spr, 0);
int textLength = Len(raw); int sprLength = Len(spr);
while (true) {
if (sprMatched
|| i == textLength) { // last pass; add whatever's in sb to list
list.Add(sb.ToStrAndClear());
if (sprMatched && i == textLength) list.Add(""); // if raw ends with spr and last pass, add emptyString as last
sprMatched = false;
}
if (i == textLength) break;
char c = CharAt(raw, i);
if (skipChar13 && c == (char)13) {i++; continue;}
if (c == spr0) { // matches first char of spr
sprPos = 1;
while (true) {
if (sprPos == sprLength) { // made it to end, must be match
sprMatched = true;
break;
}
if (i + sprPos == textLength) break; // ran out of raw; handles partial match at end of String; ab+, +-
if (CharAt(raw, i + sprPos) != CharAt(spr, sprPos)) break; // no match
sprPos++;
}
if (!sprMatched) // add partial match to sb
sb.Add(MidByLen(raw, i, sprPos));
i += sprPos;
}
else { // no spr match; just add char, increment pos
sb.AddChar(c);
i++;
}
}
return list.ToAry(String.class);
}
public static String NewCharAry(char[] ary, int bgn, int len) {return new String(ary, bgn, len);}
}

View File

@@ -13,17 +13,7 @@ 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.objects.types;
import gplx.objects.arrays.BryUtl;
import gplx.objects.primitives.BoolUtl;
import gplx.objects.primitives.ByteUtl;
import gplx.objects.primitives.CharUtl;
import gplx.objects.primitives.DoubleUtl;
import gplx.objects.primitives.FloatUtl;
import gplx.objects.primitives.IntUtl;
import gplx.objects.primitives.LongUtl;
import gplx.objects.primitives.ShortUtl;
import gplx.objects.strings.StringUtl;
package gplx.types.basics.utls;
public class TypeIds {
public static final int // SERIALIZABLE.N
IdObj = 0,
@@ -41,23 +31,22 @@ public class TypeIds {
IdDate = 12,
IdDecimal = 13,
IdArray = 14;
public static int ToIdByObj(Object o) {
if (o == null) return TypeIds.IdNull;
Class<?> type = o.getClass();
return TypeIds.ToIdByCls(type);
}
public static int ToIdByCls(Class<?> type) {
if (TypeUtl.Eq(type, IntUtl.ClsRefType)) return IdInt;
else if (TypeUtl.Eq(type, StringUtl.ClsRefType)) return IdStr;
else if (TypeUtl.Eq(type, BryUtl.ClsRefType)) return IdBry;
else if (TypeUtl.Eq(type, BoolUtl.ClsRefType)) return IdBool;
else if (TypeUtl.Eq(type, ByteUtl.ClsRefType)) return IdByte;
else if (TypeUtl.Eq(type, LongUtl.ClsRefType)) return IdLong;
else if (TypeUtl.Eq(type, DoubleUtl.ClsRefType)) return IdDouble;
else if (TypeUtl.Eq(type, FloatUtl.ClsRefType)) return IdFloat;
else if (TypeUtl.Eq(type, ShortUtl.ClsRefType)) return IdShort;
else if (TypeUtl.Eq(type, CharUtl.ClsRefType)) return IdChar;
if (ClassUtl.Eq(type, IntUtl.ClsRefType)) return IdInt;
else if (ClassUtl.Eq(type, StringUtl.ClsRefType)) return IdStr;
else if (ClassUtl.Eq(type, BryUtl.ClsRefType)) return IdBry;
else if (ClassUtl.Eq(type, BoolUtl.ClsRefType)) return IdBool;
else if (ClassUtl.Eq(type, ByteUtl.ClsRefType)) return IdByte;
else if (ClassUtl.Eq(type, LongUtl.ClsRefType)) return IdLong;
else if (ClassUtl.Eq(type, DoubleUtl.ClsRefType)) return IdDouble;
else if (ClassUtl.Eq(type, FloatUtl.ClsRefType)) return IdFloat;
else if (ClassUtl.Eq(type, ShortUtl.ClsRefType)) return IdShort;
else if (ClassUtl.Eq(type, CharUtl.ClsRefType)) return IdChar;
// else if (TypeUtl.Eq(type, DecimalUtl.ClsRefType)) return IdDecimal;
// else if (TypeUtl.Eq(type, DateUtl.ClsRefType)) return IdDate;
else return IdObj;

View File

@@ -0,0 +1,33 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.wrappers;
import gplx.types.basics.utls.BoolUtl;
public class BoolRef {
private BoolRef(boolean val) {
this.val = val;
}
public boolean Val() {return val;} private boolean val;
public boolean ValY() {return val;}
public boolean ValN() {return !val;}
public BoolRef ValSetY() {val = true; return this;}
public BoolRef ValSetN() {val = false; return this;}
public BoolRef ValSet(boolean v) {val = v; return this;}
@Override public String toString() {return BoolUtl.ToStrLower(val);}
public static BoolRef NewN() {return New(false);}
public static BoolRef NewY() {return New(true);}
public static BoolRef New(boolean val) {return new BoolRef(val);}
}

View File

@@ -0,0 +1,24 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.wrappers;
public class BoolVal {
private BoolVal(int v) {val = v;} private final int val;
public boolean Val() {return val == 1;}
public static final BoolVal
Null = new BoolVal(-1),
False = new BoolVal( 0),
True = new BoolVal( 1);
}

View File

@@ -0,0 +1,28 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.wrappers;
import gplx.types.basics.utls.ByteUtl;
import gplx.types.basics.utls.IntUtl;
public class ByteRef {
private ByteRef(byte val) {this.val = val;}
public byte Val() {return val;} private byte val;
public ByteRef ValSet(byte v) {val = v; return this;}
@Override public int hashCode() {return val;}
@Override public boolean equals(Object obj) {return obj == null ? false : val == ((ByteRef)obj).Val();}
@Override public String toString() {return IntUtl.ToStr(val);}
public static ByteRef NewZero() {return New(ByteUtl.Zero);}
public static ByteRef New(byte val) {return new ByteRef(val);}
}

View File

@@ -0,0 +1,25 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.wrappers;
import gplx.types.basics.utls.ByteUtl;
public class ByteVal {
private ByteVal(byte val) {this.val = val;}
public byte Val() {return val;} private byte val;
@Override public String toString() {return ByteUtl.ToStr(val);}
@Override public int hashCode() {return val;}
@Override public boolean equals(Object obj) {return obj == null ? false : val == ((ByteVal)obj).Val();}
public static ByteVal New(byte val) {return new ByteVal(val);}
}

View File

@@ -0,0 +1,27 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.wrappers;
import gplx.types.commons.lists.CompareAble;
import gplx.types.basics.utls.DoubleUtl;
public class DoubleVal implements CompareAble<DoubleVal> {
private DoubleVal(double val) {this.val = val;}
public double Val() {return val;} private final double val;
@Override public String toString() {return DoubleUtl.ToStr(val);}
@Override public int hashCode() {return (int)val;}
@Override public boolean equals(Object obj) {return obj == null ? false : val == ((DoubleVal)obj).Val();}
@Override public int compareTo(DoubleVal comp) {return DoubleUtl.Compare(val, comp.val);}
public static DoubleVal New(double val) {return new DoubleVal(val);}
}

View File

@@ -0,0 +1,34 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.wrappers;
import gplx.types.basics.utls.IntUtl;
public class IntRef {
private IntRef(int val) {this.val = val;}
public int Val() {return val;} public IntRef ValSet(int v) {val = v; return this;} private int val;
public int ValAddOne() {val++; return val;}
public int ValAddPost() {return val++;}
public int ValAdd(int v) {val += v; return val;}
public IntRef ValSetZero() {val = 0; return this;}
public IntRef ValSetNeg1() {val = -1; return this;}
@Override public String toString() {return IntUtl.ToStr(val);}
@Override public int hashCode() {return val;}
@Override public boolean equals(Object obj) {return val == ((IntRef)obj).Val();}
public static IntRef NewNeg1() {return new IntRef(-1);}
public static IntRef NewZero() {return new IntRef(0);}
public static IntRef New(int val) {return new IntRef(val);}
}

View File

@@ -0,0 +1,26 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.wrappers;
import gplx.types.commons.lists.CompareAble;
import gplx.types.basics.utls.IntUtl;
public class IntVal implements CompareAble<IntVal> {
public IntVal(int val) {this.val = val;}
public int Val() {return val;} private final int val;
@Override public String toString() {return IntUtl.ToStr(val);}
@Override public int hashCode() {return val;}
@Override public boolean equals(Object obj) {return obj == null ? false : val == ((IntVal)obj).Val();}
@Override public int compareTo(IntVal v) {return IntUtl.Compare(val, v.val);}
}

View File

@@ -0,0 +1,21 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.wrappers;
import gplx.types.basics.utls.ObjectUtl;
public class ObjRef {
public Object Val() {return val;} public ObjRef ValSet(Object v) {val = v; return this;} private Object val;
@Override public String toString() {return ObjectUtl.ToStrOrNull(val);}
}

View File

@@ -0,0 +1,26 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.wrappers;
public class StringRef {
private StringRef(String val) {this.val = val;}
public String Val() {return val;} public StringRef ValSet(String v) {val = v; return this;} private String val;
public StringRef ValSetNull() {return ValSet(null);}
@Override public String toString() {return val;}
public static StringRef NewEmpty() {return New("");}
public static StringRef NewNull() {return New(null);}
public static StringRef New(String val) {return new StringRef(val);}
}

View File

@@ -0,0 +1,27 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.basics.wrappers;
import gplx.types.commons.lists.CompareAble;
import gplx.types.basics.utls.StringUtl;
public class StringVal implements CompareAble<StringVal> {
private StringVal(String val) {this.val = val;}
public String Val() {return val;} private final String val;
@Override public String toString() {return val;}
@Override public int compareTo(StringVal comp) {
return StringUtl.Compare(val, comp.val);
}
public static StringVal New(String val) {return new StringVal(val);}
}

View File

@@ -0,0 +1,159 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.commons;
import gplx.types.commons.lists.CompareAble;
import gplx.types.basics.utls.IntUtl;
import gplx.types.basics.utls.ObjectUtl;
import gplx.types.basics.utls.StringUtl;
import gplx.types.errs.ErrUtl;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
public class GfoDate implements CompareAble<GfoDate> {
GfoDate(Calendar under) {this.under = under;}
GfoDate(int year, int month, int day, int hour, int minute, int second, int frac) {
this.under = NewCalendar(year, month, day, hour, minute, second, frac, IntUtl.MinValue, null);
}
GfoDate(int year, int month, int day, int hour, int minute, int second, int frac, int tzOffset, byte[] tzAbrv) {
this.under = NewCalendar(year, month, day, hour, minute, second, frac, tzOffset, tzAbrv);
}
private Calendar NewCalendar(int year, int month, int day, int hour, int minute, int second, int frac, int tzOffset, byte[] tzAbrv) {
GregorianCalendar calendar = new GregorianCalendar(year, month - MonthBase0Adj, day, hour, minute, second);
calendar.set(Calendar.MILLISECOND, frac);
if (tzOffset == IntUtl.MinValue) {
return calendar;
}
else {
long msFromEpochGmt = calendar.getTime().getTime();
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(msFromEpochGmt - tzOffset * 1000);
return cal;
}
}
public Calendar UnderCalendar() {return under;} private final Calendar under;
public int Year() {return under.get(Calendar.YEAR);}
public int Month() {return under.get(Calendar.MONTH) + MonthBase0Adj;}
public int Day() {return under.get(Calendar.DAY_OF_MONTH);}
public int Hour() {return under.get(Calendar.HOUR_OF_DAY);}
public int Minute() {return under.get(Calendar.MINUTE);}
public int Second() {return under.get(Calendar.SECOND);}
public int Frac() {return under.get(Calendar.MILLISECOND);}
public int DayOfWeek() {return under.get(Calendar.DAY_OF_WEEK) - WeekBase0Adj;}
public int DayOfYear() {return under.get(Calendar.DAY_OF_YEAR);}
public int WeekOfYear() {return under.get(Calendar.WEEK_OF_YEAR);}
public String TimezoneId() {
return "UTC"; // under.getTimeZone().getID(); // NOTE: timezone is always UTC, unless overridden by tests
}
public static int TimezoneOffsetTest = IntUtl.MinValue;
public int TimezoneOffset() {
return TimezoneOffsetTest == IntUtl.MinValue // Timezone_offset_test not overridden
? 0
: TimezoneOffsetTest;
}
public long TimestampUnix() {
long offsetFromUTC = under.getTimeZone().getOffset(0);
boolean dst = TimeZone.getDefault().inDaylightTime(under.getTime());
long dstAdj = dst ? 3600000 : 0;
return (under.getTimeInMillis() + offsetFromUTC + dstAdj) / 1000;
}
public int Segment(int idx) {
switch (idx) {
case GfoDateUtl.SegIdxYear: return this.Year();
case GfoDateUtl.SegIdxMonth: return this.Month();
case GfoDateUtl.SegIdxDay: return this.Day();
case GfoDateUtl.SegIdxHour: return this.Hour();
case GfoDateUtl.SegIdxMinute: return this.Minute();
case GfoDateUtl.SegIdxSecond: return this.Second();
case GfoDateUtl.SegIdxFrac: return this.Frac();
case GfoDateUtl.SegIdxDayOfWeek: return this.DayOfWeek();
case GfoDateUtl.SegIdxWeekOfYear: return this.WeekOfYear();
case GfoDateUtl.SegIdxDayOfYear: return this.DayOfYear();
default: throw ErrUtl.NewUnhandled(idx);
}
}
public GfoDate AddFrac(int val) {return Add(Calendar.MILLISECOND, val);}
public GfoDate AddSecond(int val) {return Add(Calendar.SECOND, val);}
public GfoDate AddMinute(int val) {return Add(Calendar.MINUTE, val);}
public GfoDate AddHour(int val) {return Add(Calendar.HOUR, val);}
public GfoDate AddDay(int val) {return Add(Calendar.DAY_OF_MONTH, val);}
public GfoDate AddMonth(int val) {return Add(Calendar.MONTH, val);}
public GfoDate AddYear(int val) {return Add(Calendar.YEAR, val);}
private GfoDate Add(int fld, int val) {
Calendar clone = (Calendar)under.clone();
clone.add(fld, val);
return new GfoDate(clone);
}
public int DiffDays(GfoDate prv) {
long diff = this.under.getTimeInMillis() - prv.under.getTimeInMillis();
return (int)(diff / (1000 * 60 * 60 * 24));
}
public GfoTimeSpan Diff(GfoDate prv) {
long diff = this.under.getTimeInMillis() - prv.under.getTimeInMillis();
return GfoTimeSpanUtl.NewFracs(diff);
}
public GfoDate ToUtc() {return ToDate(true);}
public GfoDate ToLocal() {return ToDate(false);}
private GfoDate ToDate(boolean isUtc) {
java.util.Date date = under.getTime();
java.util.TimeZone tz = under.getTimeZone();
long msFromEpochGmt = date.getTime();
int offsetFromUTC = tz.getOffset(msFromEpochGmt);
Calendar gmtCal = Calendar.getInstance();
int offset = isUtc ? -offsetFromUTC : offsetFromUTC;
gmtCal.setTimeInMillis(msFromEpochGmt + offset);
return new GfoDate(gmtCal);
}
public int[] ToSegAry() {
int[] rv = new int[7];
rv[GfoDateUtl.SegIdxYear] = this.Year();
rv[GfoDateUtl.SegIdxMonth] = this.Month();
rv[GfoDateUtl.SegIdxDay] = this.Day();
rv[GfoDateUtl.SegIdxHour] = this.Hour();
rv[GfoDateUtl.SegIdxMinute] = this.Minute();
rv[GfoDateUtl.SegIdxSecond] = this.Second();
rv[GfoDateUtl.SegIdxFrac] = this.Frac();
return rv;
}
public String ToStrGplx() {return ToStrFmt("yyyyMMdd_HHmmss.fff");}
public String ToStrGplxLong() {return ToStrFmt("yyyy-MM-dd HH:mm:ss.fff");}
public String ToStrFmt_HHmmss() {return ToStrFmt("HH:mm:ss");}
public String ToStrFmt_HHmm() {return ToStrFmt("HH:mm");}
public String ToStrFmt_yyyyMMdd() {return ToStrFmt("yyyy-MM-dd");}
public String ToStrFmt_yyyyMMdd_HHmmss() {return ToStrFmt("yyyyMMdd_HHmmss");}
public String ToStrFmt_yyyyMMdd_HHmmss_fff() {return ToStrFmt("yyyyMMdd_HHmmss.fff");}
public String ToStrFmt_yyyy_MM_dd_HH_mm() {return ToStrFmt("yyyy-MM-dd HH:mm");}
public String ToStrFmt_yyyy_MM_dd_HH_mm_ss() {return ToStrFmt("yyyy-MM-dd HH:mm:ss");}
public String ToStrFmtIso8561() {return ToStrFmt("yyyy-MM-dd HH:mm:ss");}
public String ToStrFmtIso8561WithTz() {return ToStrFmt("yyyy-MM-dd'T'HH:mm:ss'Z'");}
public String ToStrFmt(String fmt) {
fmt = fmt.replace("f", "S");
SimpleDateFormat sdf = new SimpleDateFormat(fmt);
return sdf.format(under.getTime());
}
public String ToStrTz() {
SimpleDateFormat sdf = new SimpleDateFormat("Z");
String timeZone = sdf.format(under.getTime());
return StringUtl.Mid(timeZone, 0, 3) + ":" + StringUtl.Mid(timeZone, 3, StringUtl.Len(timeZone));
}
public boolean Eq(GfoDate v) {GfoDate comp = v; return ObjectUtl.Eq(under.getTimeInMillis(), comp.under.getTimeInMillis());}
@Override public int compareTo(GfoDate comp) {return under.compareTo(comp.under);}
@Override public String toString() {return ToStrGplxLong();}
private static final int
MonthBase0Adj = 1,
WeekBase0Adj = 1; // -1 : Base0; NOTE: dotnet/php is also Sunday=0
}

View File

@@ -0,0 +1,40 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.commons;
import java.util.GregorianCalendar;
public class GfoDateNow {
private static final GfoDate dflt = GfoDateUtl.ParseGplx("2001-01-01 00:00:00.000");
public static GfoDate DfltAddMin(int v) {return dflt.AddMinute(v);}
public static void AutoincrementSetN() {autoincrement = false;} private static boolean autoincrement = true;
public static void ManualSet(GfoDate v) {manual = v;} private static GfoDate manual;
public static void ManualSetY() {manual = dflt;}
public static void ManualSetN() {
manual = null;
autoincrement = true;
}
public static void ManualSetAndFreeze(GfoDate v) {
manual = v;
autoincrement = false;
}
public static GfoDate Get() {
if (manual == null)
return new GfoDate(new GregorianCalendar());
GfoDate rv = manual;
if (autoincrement) manual = rv.AddMinute(1); // simulate passage of time by increasing manual by 1 minute with each call
return rv;
}
public static GfoDate GetForce() {return new GfoDate(new GregorianCalendar());} // ignore manual and force get of real time
}

View File

@@ -0,0 +1,76 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.commons;
import gplx.types.basics.utls.BryUtl;
import gplx.types.basics.constants.AsciiByte;
public class GfoDateParser {
private static int[] MaxLens = new int[]
{ 4 // y
, 2 // M
, 2 // d
, 2 // H
, 2 // m
, 2 // s
, 3 // S (fracs)
, 0 // (TimeZone)
};
private final IntBldr intBldr = new IntBldr(4);
public int[] ParseIso8651Like(String raw_str) {
int[] tmpRv = new int[7];
ParseIso8651Like(tmpRv, raw_str);
return tmpRv;
}
public void ParseIso8651Like(int[] rv, String rawStr) {
byte[] rawBry = BryUtl.NewU8(rawStr);
ParseIso8651Like(rv, rawBry, 0, rawBry.length);
}
public void ParseIso8651Like(int[] rv, byte[] src, int bgn, int end) {
/*
1981-04-05T14:30:30.000-05:00 ISO 8601: http://en.wikipedia.org/wiki/ISO_8601
1981.04.05 14.30.30.000-05.00 ISO 8601 loose
99991231_235959.999 gplx
yyyy-MM-ddTHH:mm:ss.fffzzzz Format String
*/
// clear array
int rvLen = rv.length;
for (int i = 0; i < rvLen; i++)
rv[i] = 0;
int pos = bgn, rvIdx = 0, intLen = 0, maxLen = MaxLens[rvIdx];
while (true) {
int intVal = -1;
byte b = pos < end ? src[pos] : AsciiByte.Null;
switch (b) {
case AsciiByte.Num0: case AsciiByte.Num1: case AsciiByte.Num2: case AsciiByte.Num3: case AsciiByte.Num4:
case AsciiByte.Num5: case AsciiByte.Num6: case AsciiByte.Num7: case AsciiByte.Num8: case AsciiByte.Num9:
intVal = b - AsciiByte.Num0; // convert ascii to val; EX: 49 -> 1
intLen = intBldr.Add(intVal);
break;
}
if ( (intVal == -1 && intLen > 0) // char is not number && number exists (ignore consecutive delimiters: EX: "1981 01")
|| intLen == maxLen) { // maxLen reached; necessary for gplxFormat
rv[rvIdx++] = intBldr.ToIntAndClear();
if (rvIdx == 7) // past frac; break;
break;
intLen = 0;
maxLen = MaxLens[rvIdx];
}
if (pos == end)
break;
++pos;
}
}
}

View File

@@ -0,0 +1,118 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.commons;
import gplx.types.errs.ErrUtl;
import gplx.types.basics.utls.IntUtl;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
public class GfoDateUtl {
public static final String ClsRefName = "Date";
public static final Class<?> ClsRefType = GfoDate.class;
public static final GfoDate
MinValue = new GfoDate( 1, 1, 1, 0, 0, 0, 0),
MaxValue = new GfoDate(9999, 12, 31, 23, 59, 59, 999);
private static int [] DaysInMonthAry = {31,28,31,30,31,30,31,31,30,31,30,31};
public static int DaysInMonth(int year, int month) {
int rv = DaysInMonthAry[month - IntUtl.Base1];
if (rv == 28 && IsLeapYear(year)) rv = 29;
return rv;
}
public static boolean IsLeapYear(int year) {
if (year % 4 != 0) return false;
else if (year % 400 == 0) return true;
else if (year % 100 == 0) return false;
else return true;
}
public static GfoDate New(int year, int month, int day, int hour, int minute, int second, int frac) {return new GfoDate(year, month, day, hour, minute, second, frac);}
public static GfoDate NewBySegs(int[] ary) {
int ary_len = ary.length;
int y = ary_len > 0 ? ary[0] : 1;
int M = ary_len > 1 ? ary[1] : 1;
int d = ary_len > 2 ? ary[2] : 1;
int h = ary_len > 3 ? ary[3] : 0;
int m = ary_len > 4 ? ary[4] : 0;
int s = ary_len > 5 ? ary[5] : 0;
int f = ary_len > 6 ? ary[6] : 0;
return new GfoDate(y, M, d, h, m, s, f);
}
public static GfoDate NewDateByBits(int y, int m, int d, int h, int i, int s, int us, int tzOffset, byte[] tzAbrv) {
return new GfoDate(y, m, d, h, i, s, us/1000, tzOffset, tzAbrv);
}
public static GfoDate NewByCalendar(GregorianCalendar v) {return new GfoDate(v);}
public static GfoDate NewUnixtimeUtcSeconds(long v) {return NewUnixtimeUtcMs(v * 1000);}
public static GfoDate NewUnixtimeUtcMs(long v) {return NewUnixtimeLclMs(v).ToUtc();}
public static GfoDate NewUnixtimeLclMs(long v) {
GregorianCalendar c = new GregorianCalendar();
c.setTimeInMillis(v);
return new GfoDate(c);
}
public static GfoDate NewByDb(Object v) {
if (v instanceof String) {
return GfoDateUtl.ParseIso8561((String)v);
}
Timestamp ts = (Timestamp)v;
Calendar gc = Calendar.getInstance();
gc.setTimeInMillis(ts.getTime());
return new GfoDate(gc);
}
public static GfoDate Parse(String raw) {
SimpleDateFormat sdf = new SimpleDateFormat();
Date d;
try {d = sdf.parse(raw);}
catch (ParseException e) {throw ErrUtl.NewArgs("failed to parse to DateAdp", "raw", raw);}
GregorianCalendar cal = (GregorianCalendar)Calendar.getInstance();
cal.setTime(d);
return NewByCalendar(cal);
}
public static GfoDate ParseFmtOr(String raw, String fmt, GfoDate or) {
try {return ParseFmt(raw, fmt);}
catch (Exception e) {return or;}
}
public static GfoDate ParseFmt(String raw, String fmt) {
fmt = fmt.replace('t', 'a'); // AM/PM
fmt = fmt.replace('f', 'S'); // milliseconds
SimpleDateFormat sdf = new SimpleDateFormat(fmt, Locale.US);
Date d = null;
try {d = sdf.parse(raw);}
catch (ParseException e) {throw ErrUtl.NewArgs("failed to parse to DateAdp", "raw", raw, "fmt", fmt);}
GregorianCalendar cal = (GregorianCalendar)Calendar.getInstance();
cal.setTime(d);
return NewByCalendar(cal);
}
public static GfoDate ParseIso8561Or(String raw, GfoDate or) {
try {return ParseIso8561(raw);}
catch (Exception e) {return or;}
}
public static GfoDate ParseGplx(String raw) {return ParseIso8561(raw);} // NOTE: for now, same as ParseIso8561
public static GfoDate ParseIso8561(String raw) {
GfoDateParser dateParser = new GfoDateParser();
int[] ary = dateParser.ParseIso8651Like(raw);
if (ary[1] < 1 || ary[1] > 12) return GfoDateUtl.MinValue; // guard against invalid month
if (ary[2] < 1 || ary[2] > 31) return GfoDateUtl.MinValue; // guard against invalid day
return new GfoDate(ary[0], ary[1], ary[2], ary[3], ary[4], ary[5], ary[6]);
}
public static final int
SegIdxYear = 0, SegIdxMonth = 1, SegIdxDay = 2, SegIdxHour = 3, SegIdxMinute = 4, SegIdxSecond = 5,
SegIdxFrac = 6, SegIdxDayOfWeek = 7, SegIdxWeekOfYear = 8, SegIdxDayOfYear = 9, SegIdxTz = 10, SegIdxMaxLen = 11;
public static final String
FmtIso8561DateTime = "yyyy-MM-dd HH:mm:ss",
Fmt_yyyyMMdd = "yyyyMMdd";
}

View File

@@ -0,0 +1,95 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.commons;
import gplx.types.commons.lists.CompareAble;
import gplx.types.basics.utls.MathUtl;
import gplx.types.basics.utls.ObjectUtl;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
public class GfoDecimal implements CompareAble<GfoDecimal> {
private final BigDecimal under;
GfoDecimal(BigDecimal v) {this.under = v;}
GfoDecimal(int v) {this.under = new BigDecimal(v);}
public Object Under() {return under;}
public BigDecimal UnderAsNative() {return under;}
public int Frac1000() {return (int)(under.movePointRight(3).floatValue() % 1000);}
public GfoDecimal Floor() {return GfoDecimalUtl.NewByInt(this.ToInt());}
public GfoDecimal Add(GfoDecimal v) {return new GfoDecimal(under.add(v.under, GfoDecimalUtl.ContextGfoDefault));}
public GfoDecimal Subtract(GfoDecimal v) {return new GfoDecimal(under.subtract(v.under, GfoDecimalUtl.ContextGfoDefault));}
public GfoDecimal Multiply(GfoDecimal v) {return new GfoDecimal(under.multiply(v.under));}
public GfoDecimal Multiply(long v) {return new GfoDecimal(under.multiply(new BigDecimal(v)));}
public GfoDecimal Divide(GfoDecimal v) {return new GfoDecimal(under.divide(v.under, GfoDecimalUtl.ContextGfoDefault));}
public GfoDecimal Mod(GfoDecimal v) {return new GfoDecimal(under.remainder(v.under, GfoDecimalUtl.ContextGfoDefault));}
public GfoDecimal Abs() {return new GfoDecimal(under.abs(GfoDecimalUtl.ContextGfoDefault));}
public GfoDecimal Pow(int v) {return new GfoDecimal(under.pow(v, GfoDecimalUtl.ContextGfoDefault));}
public GfoDecimal Sqrt() {return new GfoDecimal(new BigDecimal(MathUtl.Sqrt(under.doubleValue())));}
public GfoDecimal Truncate() {return new GfoDecimal(under.intValue());}
public GfoDecimal RoundNative(int v) {return new GfoDecimal(under.setScale(v, RoundingMode.HALF_UP));}
public GfoDecimal Round(int v) {
BigDecimal new_val = null;
if (v > 0) {
new_val = under.setScale(v, RoundingMode.HALF_UP);
}
else {
int actl_places = under.precision() - under.scale();
int reqd_places = -v;
if (reqd_places < actl_places)
new_val = under.round(new java.math.MathContext(actl_places - reqd_places, RoundingMode.HALF_UP));
else if (reqd_places == actl_places) {
int base_10 = (int)MathUtl.Pow(10, reqd_places - 1);
if (under.intValue() / base_10 < 5)
new_val = BigDecimal.ZERO;
else
new_val = new BigDecimal(MathUtl.Pow(10, reqd_places));
}
else
new_val = BigDecimal.ZERO;
}
return new GfoDecimal(new_val);
}
public GfoDecimal RoundToDefaultPrecision() {return new GfoDecimal(under.round(GfoDecimalUtl.ContextGfoDefault));}
public boolean CompGte(GfoDecimal v) {return under.doubleValue() >= v.under.doubleValue();}
public boolean CompLte(GfoDecimal v) {return under.doubleValue() <= v.under.doubleValue();}
public boolean CompLte(int v) {return under.doubleValue() <= v;}
public boolean CompGt(GfoDecimal v) {return under.doubleValue() > v.under.doubleValue();}
public boolean CompGt(int v) {return under.doubleValue() > v;}
public boolean CompLt(GfoDecimal v) {return under.doubleValue() < v.under.doubleValue();}
public boolean CompLt(int v) {return under.doubleValue() < v;}
public boolean Eq(GfoDecimal v) {return v.under.doubleValue() == under.doubleValue();}
public boolean Eq(int v) {return under.doubleValue() == v;}
public int ToInt() {return (int)under.doubleValue();}
public long ToLong() {return (long)under.doubleValue();}
public long ToLongMult1000() {return under.movePointRight(3).longValue();}
public double ToDouble() {return under.doubleValue();}
public String ToStr(String fmt) {return new DecimalFormat(fmt).format(under);}
public String ToStr() {
BigDecimal tmp = under;
int tmp_scale = tmp.scale();
if (tmp_scale <= -14) // NOTE: if large number, call .toString which will return exponential notaion (1E##) instead of literal (1000....); 14 matches MW code; DATE:2015-04-10
return tmp.toString();
if (tmp_scale > 14) // NOTE: if small number, round down to remove excessive zeroes; 14 matches PHP/C# values more closely; RoundingMode.Down for same reason; see E, Pi tests
tmp = tmp.setScale(14, RoundingMode.DOWN);
return tmp
.stripTrailingZeros() // NOTE: stripTrailingZeros for exp tests; EX: 120.0 -> 120; 0.01200000000000 -> .012
.toPlainString(); // NOTE: toPlainString b/c stripTrailingZeros now converts 120 to 1.2E+2 (and any other value that is a multiple of 10)
}
@Override public int compareTo(GfoDecimal comp) {return under.compareTo(comp.under);}
@Override public String toString() {return under.toString();}
@Override public boolean equals(Object obj) {GfoDecimal comp = (GfoDecimal)obj; return ObjectUtl.Eq(under, comp.under);}
@Override public int hashCode() {return under.hashCode();}
}

View File

@@ -0,0 +1,88 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.commons;
import gplx.types.errs.ErrUtl;
import gplx.types.basics.utls.FloatUtl;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
public class GfoDecimalUtl {
public static final String Cls_val_name = "decimal";
public static final Class<?> Cls_ref_type = GfoDecimal.class;
public static final GfoDecimal
Zero = new GfoDecimal(0),
One = new GfoDecimal(1),
Neg1 = new GfoDecimal(-1),
E = NewByDouble(Math.E),
PI = NewByDouble(Math.PI);
public static GfoDecimal CastOrNull(Object obj) {return obj instanceof GfoDecimal ? (GfoDecimal)obj : null;}
public static GfoDecimal NewByBase1000(long v) {return NewByDivide(v, 1000);}
public static GfoDecimal NewByParts1000(long num, int frc) {return NewByDivide((num * (1000)) + frc, 1000);}
public static GfoDecimal NewByDivideSafe(long lhs, long rhs) {return rhs == 0 ? Zero : NewByDivide(lhs, rhs);}
public static GfoDecimal NewByDivide(long lhs, long rhs) {
return new GfoDecimal(new BigDecimal(lhs).divide(new BigDecimal(rhs), ContextGfoDefault));
}
public static GfoDecimal NewByInt(int v) {return new GfoDecimal(new BigDecimal(v));}
public static GfoDecimal NewByLong(long v) {return new GfoDecimal(new BigDecimal(v));}
public static GfoDecimal NewByFloat(float v) {return new GfoDecimal(new BigDecimal(v));}
public static GfoDecimal NewByDouble(double v) {return new GfoDecimal(new BigDecimal(v));}
public static GfoDecimal NewByDoubleThruStr(double v) {return new GfoDecimal(BigDecimal.valueOf(v));}
public static GfoDecimal NewDb(Object v) {return new GfoDecimal((BigDecimal)v);}
public static GfoDecimal NewByPow10(int v) {return new GfoDecimal(new BigDecimal(1).scaleByPowerOfTen(v));}
public static GfoDecimal NewByParts(long num, int frc) {
int pow10 = ToPow10(frc);
return NewByDivide((num * (pow10)) + frc, pow10);
}
private static int ToPow10(int v) {
if (v > -1 && v < 10) return 10;
else if (v > 9 && v < 100) return 100;
else if (v > 99 && v < 1000) return 1000;
else if (v > 999 && v < 10000) return 10000;
else if (v > 9999 && v < 100000) return 100000;
else if (v > 99999 && v < 1000000) return 1000000;
else if (v > 999999 && v < 10000000) return 10000000;
else if (v > 9999999 && v < 100000000) return 100000000;
else if (v > 99999999 && v < 1000000000) return 1000000000;
else throw ErrUtl.NewArgs("value must be between 0 and 1 billion", "v", v);
}
public static GfoDecimal Parse(String raw) {
try {
DecimalFormat nf = (DecimalFormat)NumberFormat.getInstance(Locale.US); // always parse as US format; EX:".9" should not be ",9" in german; DATE:2016-01-31
nf.setParseBigDecimal(true);
// 2020-08-27|ISSUE#:565|Parse 'e' as 'E'; PAGE:en.w:Huntington_Plaza
if (raw.contains("e")) {
raw = raw.replace("e", "E");
}
// 2021-02-13|ISSUE#:838|Parse '.' as '0.'; PAGE:en.w:2019_FIVB_Volleyball_Women%27s_Challenger_Cup#Pool_A
if (raw.startsWith(".")) {
raw = "0" + raw;
}
BigDecimal bd = (BigDecimal)nf.parse(raw);
return new GfoDecimal(bd);
} catch (ParseException e) {
throw ErrUtl.NewArgs("Decimal_adp_", "parse to decimal failed", "raw", raw);
}
}
public static String CalcPctStr(long dividend, long divisor, String fmt) {
if (divisor == 0) return "%ERR";
return GfoDecimalUtl.NewByFloat(FloatUtl.Div(dividend, divisor) * 100).ToStr(fmt) + "%";
}
public static final MathContext ContextGfoDefault = new MathContext(14, RoundingMode.HALF_UP); // changed from 28 to 14; DATE:2015-07-31
}

View File

@@ -0,0 +1,22 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.commons;
import java.util.UUID;
public class GfoGuid {
public GfoGuid(UUID guid) {this.guid = guid;} private final UUID guid;
public String ToStr() {return guid.toString();}
@Override public String toString() {return guid.toString();}
}

View File

@@ -0,0 +1,23 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.commons;
public class GfoGuidUtl {
public static final String Cls_ref_name = "Guid";
public static final GfoGuid Empty = Parse("00000000-0000-0000-0000-000000000000");
public static String NewAsstr() {return New().ToStr();}
public static GfoGuid New() {return new GfoGuid(java.util.UUID.randomUUID());}
public static GfoGuid Parse(String s) {return new GfoGuid(java.util.UUID.fromString(s));}
}

View File

@@ -13,7 +13,7 @@ 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.objects;
package gplx.types.commons;
public class GfoKeyVal<K, V> {
public GfoKeyVal(K key, V val) {
this.key = key;

View File

@@ -0,0 +1,22 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.commons;
import java.util.Random;
public class GfoRandom {
private final Random under;
public GfoRandom(Random v) {this.under = v;}
public int Next(int max) {return under.nextInt(max);}
}

View File

@@ -13,11 +13,11 @@ 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.objects.types;
public class TypeUtl {
public static boolean Eq(Class<?> lhs, Class<?> rhs) {// NOTE: same as ObjectUtl.Eq
if (lhs == null && rhs == null) return true;
else if (lhs == null || rhs == null) return false;
else return lhs.equals(rhs);
package gplx.types.commons;
import java.util.Random;
public class GfoRandomUtl {
public static GfoRandom New() {
Random random = new Random(System.currentTimeMillis());
return new GfoRandom(random);
}
}

View File

@@ -0,0 +1,79 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.commons;
import gplx.types.commons.lists.CompareAble;
import gplx.types.commons.lists.CompareAbleUtl;
import gplx.types.basics.strings.bfrs.GfoStringBldr;
import gplx.types.basics.utls.IntUtl;
import gplx.types.basics.utls.ObjectUtl;
public class GfoTimeSpan implements CompareAble<GfoTimeSpan> {
public GfoTimeSpan(long fracs) {this.fracs = fracs;}
public long Fracs() {return fracs;} private final long fracs;
public int FracsAsInt() {return (int)fracs;}
public GfoDecimal TotalDays() {return GfoDecimalUtl.NewByDivide(fracs, GfoTimeSpanUtl.Divisors[GfoTimeSpanUtl.Idx_Hour] * 24);}
public GfoDecimal TotalHours() {return GfoDecimalUtl.NewByDivide(fracs, GfoTimeSpanUtl.Divisors[GfoTimeSpanUtl.Idx_Hour]);}
public GfoDecimal TotalMins() {return GfoDecimalUtl.NewByDivide(fracs, GfoTimeSpanUtl.Divisors[GfoTimeSpanUtl.Idx_Min]);}
public GfoDecimal TotalSecs() {return GfoDecimalUtl.NewByDivide(fracs, GfoTimeSpanUtl.Divisors[GfoTimeSpanUtl.Idx_Sec]);}
public int[] Units() {return GfoTimeSpanUtl.SplitLong(fracs, GfoTimeSpanUtl.Divisors);}
public GfoTimeSpan Add(GfoTimeSpan val) {return new GfoTimeSpan(fracs + val.fracs);}
public GfoTimeSpan AddFracs(long val) {return new GfoTimeSpan(fracs + val);}
public GfoTimeSpan AddUnit(int idx, int val) {
int[] units = GfoTimeSpanUtl.SplitLong(fracs, GfoTimeSpanUtl.Divisors);
units[idx] += val;
int sign = fracs >= 0 ? 1 : -1;
long rv = sign * GfoTimeSpanUtl.MergeLong(units, GfoTimeSpanUtl.Divisors);
return GfoTimeSpanUtl.NewFracs(rv);
}
public GfoTimeSpan Subtract(GfoTimeSpan val) {return new GfoTimeSpan(fracs - val.fracs);}
public boolean Eq(Object o) {
GfoTimeSpan comp = (GfoTimeSpan)o; if (comp == null) return false;
return fracs == comp.fracs;
}
public String ToStr() {return GfoTimeSpanUtl.ToStr(fracs, GfoTimeSpanUtl.Fmt_Default);}
public String ToStr(String format) {return GfoTimeSpanUtl.ToStr(fracs, format);}
public String ToStrUiAbrv() {
if (fracs == 0) return "0" + UnitAbbrv(0);
int[] units = Units();
boolean started = false;
GfoStringBldr sb = new GfoStringBldr();
for (int i = units.length - 1; i > -1; i--) {
int unit = units[i];
if (!started) {
if (unit == 0)
continue;
else
started = true;
}
if (sb.Len() != 0) sb.Add(" ");
sb.AddObj(unit).Add(UnitAbbrv(i));
}
return sb.ToStr();
}
private String UnitAbbrv(int i) {
switch (i) {
case 0: return "f";
case 1: return "s";
case 2: return "m";
case 3: return "h";
default: return "unknown:<" + IntUtl.ToStr(i) + ">";
}
}
@Override public int compareTo(GfoTimeSpan comp) {return CompareAbleUtl.Compare_obj(fracs, comp.fracs);}
@Override public String toString() {return ToStr(GfoTimeSpanUtl.Fmt_Default);}
@Override public boolean equals(Object obj) {GfoTimeSpan comp = (GfoTimeSpan)obj; return ObjectUtl.Eq(fracs, comp.fracs);}
@Override public int hashCode() {return new Long(fracs).hashCode();}
}

View File

@@ -0,0 +1,161 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.commons;
import gplx.types.basics.utls.ArrayUtl;
import gplx.types.basics.utls.BryUtl;
import gplx.types.basics.constants.AsciiByte;
import gplx.types.basics.strings.bfrs.GfoStringBldr;
import gplx.types.basics.utls.IntUtl;
import gplx.types.basics.utls.LongUtl;
import gplx.types.basics.utls.MathUtl;
import gplx.types.basics.utls.StringUtl;
public class GfoTimeSpanUtl {
public static final GfoTimeSpan
Zero = new GfoTimeSpan(0),
Null = new GfoTimeSpan(-1);
public static final long ParseNull = LongUtl.MinValue;
public static GfoTimeSpan NewFracs(long val) {return new GfoTimeSpan(val);}
public static GfoTimeSpan NewSeconds(double seconds) {
long fracs = (long)(seconds * Divisors[Idx_Sec]);
return new GfoTimeSpan(fracs);
}
public static GfoTimeSpan NewSeconds(GfoDecimal seconds) {return new GfoTimeSpan(seconds.ToLongMult1000());}
public static GfoTimeSpan Parse(String raw) {
byte[] bry = BryUtl.NewU8(raw);
long fracs = ParseToFracs(bry, 0, bry.length, false);
return fracs == ParseNull ? null : GfoTimeSpanUtl.NewFracs(fracs);
}
public static long ParseToFracs(byte[] raw, int bgn, int end, boolean fail_if_ws) {
int sign = 1, val_f = 0, val_s = 0, val_m = 0, val_h = 0, colon_pos = 0, unit_val = 0, unit_multiple = 1;
for (int i = end - 1; i >= bgn; i--) { // start from end; fracs should be lowest unit
byte b = raw[i];
switch (b) {
case AsciiByte.Num0: case AsciiByte.Num1: case AsciiByte.Num2: case AsciiByte.Num3: case AsciiByte.Num4:
case AsciiByte.Num5: case AsciiByte.Num6: case AsciiByte.Num7: case AsciiByte.Num8: case AsciiByte.Num9:
int unit_digit = AsciiByte.ToA7Int(b);
unit_val = (unit_multiple == 1) ? unit_digit : unit_val + (unit_digit * unit_multiple);
switch (colon_pos) {
case 0: val_s = unit_val; break;
case 1: val_m = unit_val; break;
case 2: val_h = unit_val; break;
default: return ParseNull; // only hour:minute:second supported for ':' separator; ':' count should be <= 2
}
unit_multiple *= 10;
break;
case AsciiByte.Dot:
double factor = (double)1000 / (double)unit_multiple; // factor is necessary to handle non-standard decimals; ex: .1 -> 100; .00199 -> .001
val_f = (int)((double)val_s * factor); // move val_s unit_val to val_f; logic is indirect, b/c of differing inputs: "123" means 123 seconds; ".123" means 123 fractionals
val_s = 0;
unit_multiple = 1;
break;
case AsciiByte.Colon:
colon_pos++;
unit_multiple = 1;
break;
case AsciiByte.Dash:
if (i == 0 && unit_val > 0) // only if first char && unit_val > 0
sign = -1;
break;
case AsciiByte.Space: case AsciiByte.Tab: case AsciiByte.Nl: case AsciiByte.Cr:
if (fail_if_ws) return ParseNull;
break;
default:
return ParseNull; // invalid char; return null;
}
}
return sign * (val_f + (val_s * Divisors[1]) + (val_m * Divisors[2]) + (val_h * Divisors[3]));
}
public static String ToStr(long frc, String fmt) {
GfoStringBldr sb = new GfoStringBldr();
int[] units = SplitLong(frc, Divisors);
if (StringUtl.Eq(fmt, GfoTimeSpanUtl.Fmt_Short)) {
for (int i = Idx_Hour; i > -1; i--) {
int val = units[i];
if (val == 0 && i == Idx_Hour) continue; // skip hour if 0; ex: 01:02, instead of 00:01:02
if (i == Idx_Frac) continue; // skip frac b/c fmt is short
if (sb.Len() > 0) // sb already has unit; add delimiter
sb.Add(Sprs[i]);
if (val < 10) // zeroPad
sb.Add("0");
sb.Add(IntUtl.ToStr(val));
}
return sb.ToStrAndClear();
}
boolean fmt_fracs = !StringUtl.Eq(fmt, GfoTimeSpanUtl.Fmt_NoFractionals);
boolean fmt_padZeros = StringUtl.Eq(fmt, GfoTimeSpanUtl.Fmt_PadZeros);
if (frc == 0) return fmt_padZeros ? "00:00:00.000" : "0";
int[] padZerosAry = ZeroPadding;
boolean first = true;
String dlm = "";
int zeros = 0;
if (frc < 0) sb.Add("-"); // negative sign
for (int i = Idx_Hour; i > -1; i--) { // NOTE: "> Idx_Frac" b/c frc will be handled below
int val = units[i];
if (i == Idx_Frac // only write fracs...
&& !(val == 0 && fmt_padZeros) // ... if val == 0 && fmt is PadZeros
&& !(val != 0 && fmt_fracs) // ... or val != 0 && fmt is PadZeros or Default
) continue;
if (first && val == 0 && !fmt_padZeros) continue; // if first and val == 0, don't full pad (avoid "00:")
zeros = first && !fmt_padZeros ? 1 : padZerosAry[i]; // if first, don't zero pad (avoid "01")
dlm = first ? "" : Sprs[i]; // if first, don't use dlm (avoid ":01")
sb.Add(dlm);
sb.Add(IntUtl.ToStrPadBgnZero(val, zeros));
first = false;
}
return sb.ToStr();
}
public static int[] SplitLong(long fracs, int[] divisors) {
int divLength = ArrayUtl.Len(divisors);
int[] rv = new int[divLength];
long cur = MathUtl.Abs(fracs); // NOTE: Abs necessary for toStr; EX: -1234 -> 1234 -> -1s 234f
for (int i = divLength - 1; i > -1; i--) {
int divisor = divisors[i];
long factor = cur / divisor;
rv[i] = (int)factor;
cur -= (factor * divisor);
}
return rv;
}
public static long MergeLong(int[] vals, int[] divisors) {
long rv = 0; int valLength = ArrayUtl.Len(vals);
for (int i = 0; i < valLength; i++) {
rv += vals[i] * divisors[i];
}
return rv;
}
public static final String
Fmt_PadZeros = "00:00:00.000", // u,h00:m00:s00.f000
Fmt_Short = "short", // u,h##:m#0:s00;
Fmt_Default = "0.000", // v,#.000
Fmt_NoFractionals = "0"; // v,#
public static final int[] Divisors =
{ 1 // 1 fracs
, 1000 // 1,000 fracs in a second
, 60000 // 60,000 fracs in a minute (60 seconds * 1,000)
, 3600000 // 3,600,000 fracs in an hour (60 minutes * 60,000)
};
public static final String MajorDelimiter = ":";
public static final int
Idx_Frac = 0,
Idx_Sec = 1,
Idx_Min = 2,
Idx_Hour = 3;
private static int[] ZeroPadding = {3, 2, 2, 2,};
private static String[] Sprs = {".", MajorDelimiter, MajorDelimiter, "",};
public static final double RatioFracsToSecs = 1000;
}

View File

@@ -0,0 +1,64 @@
package gplx.types.commons;
import gplx.types.errs.ErrUtl;
public class IntBldr {
private int[] digits;
private int idx, digitsLen;
private int sign = 1;
public IntBldr(int digitsMax) {
this.digits = new int[digitsMax];
this.digitsLen = digitsMax;
}
public void Clear() {idx = 0; sign = 1;}
public int Add(char c) {
if (idx > digitsLen - 1) throw ErrUtl.NewArgs("index is out of bound", "idx", idx, "len", digitsLen);
digits[idx++] = ToIntByChar(c);
return idx;
}
public int Add(int i) {
if (idx > digitsLen - 1) throw ErrUtl.NewArgs("index is out of bound", "idx", idx, "len", digitsLen);
digits[idx++] = i;
return idx;
}
public int ToInt() {
int rv = 0, exponent = 1;
for (int i = idx - 1; i > -1; i--) {
int digit = digits[i];
if (digit < 0) throw ErrUtl.NewArgs("invalid char", "char", (char)-digits[i], "ascii", -digits[i]);
rv += digit * exponent;
exponent *= 10;
}
return sign * rv;
}
public int ToIntAndClear() {
int rv = ToInt();
this.Clear();
return rv;
}
public int Parse(String raw) {
ParseStr(raw);
try {return ToInt();}
catch (Exception exc) {throw ErrUtl.NewParse(int.class, raw);}
}
public boolean ParseTry(String raw) {
ParseStr(raw);
for (int i = 0; i < idx; i++)
if (digits[i] < 0) return false;
return true;
}
private void ParseStr(String raw) {
this.Clear();
int rawLength = raw.length();
for (int i = 0; i < rawLength; i++) {
char c = raw.charAt(i);
if (i == 0 && c == '-')
sign = -1;
else
Add(c);
}
}
private int ToIntByChar(char c) {
if (c == '0') return 0; else if (c == '1') return 1; else if (c == '2') return 2; else if (c == '3') return 3; else if (c == '4') return 4;
else if (c == '5') return 5; else if (c == '6') return 6; else if (c == '7') return 7; else if (c == '8') return 8; else if (c == '9') return 9;
else return -(int)c; // error handling: don't throw error; store ascii value in digit and throw if needed
}
}

View File

@@ -0,0 +1,40 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.commons;
import gplx.frameworks.objects.ToStrAble;
import gplx.types.basics.utls.ObjectUtl;
import gplx.types.basics.utls.BryUtl;
import gplx.types.basics.utls.TypeIds;
public class KeyVal implements ToStrAble { // DEPRECATED
public KeyVal(int keyTid, Object key, Object val) {this.keyTid = keyTid; this.key = key; this.val = val;}
public int KeyTid() {return keyTid;} private int keyTid;
public Object KeyAsObj() {return key;} private Object key;
public KeyVal KeySet(Object v) {this.key = v; return this;}
public String KeyToStr() {return ObjectUtl.ToStrOrNull(key);}
public Object Val() {return val;} private Object val;
public String ValToStrOrEmpty() {return ObjectUtl.ToStrOrEmpty(val);}
public String ValToStrOrNull() {return ObjectUtl.ToStrOrNull(val);}
public byte[] ValToBry() {return BryUtl.NewU8(ObjectUtl.ToStrOrNull(val));}
public KeyVal ValSet(Object v) {this.val = v; return this;}
public String ToStr() {return KeyToStr() + "=" + ObjectUtl.ToStrOrNullMark(val);}
@Override public String toString() {return ToStr();}
public static KeyVal As(Object obj) {return obj instanceof KeyVal ? (KeyVal)obj : null;}
public static KeyVal NewStr(String key) {return new KeyVal(TypeIds.IdStr, key, key);}
public static KeyVal NewStr(String key, Object val) {return new KeyVal(TypeIds.IdStr, key, val);}
public static KeyVal NewInt(int key, Object val) {return new KeyVal(TypeIds.IdInt, key, val);}
public static KeyVal NewObj(Object key, Object val) {return new KeyVal(TypeIds.IdObj, key, val);}
}

View File

@@ -0,0 +1,42 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.commons;
import gplx.types.basics.strings.bfrs.GfoStringBldr;
import gplx.types.basics.utls.ClassUtl;
import gplx.types.basics.utls.ObjectUtl;
public class KeyValUtl {
public static final KeyVal[] AryEmpty = new KeyVal[0];
public static KeyVal[] Ary(KeyVal... ary) {return ary;}
public static String AryToStr(KeyVal... ary) {
GfoStringBldr sb = new GfoStringBldr();
int len = ary.length;
for (int i = 0; i < len; i++) {
KeyVal itm = ary[i];
if (itm == null) {
sb.Add("<<NULL>>");
continue;
}
sb.Add(itm.KeyToStr()).Add("=");
Object itm_val = itm.Val();
if (ClassUtl.EqByObj(KeyVal[].class, itm_val))
sb.Add(AryToStr((KeyVal[])itm_val));
else
sb.Add(ObjectUtl.ToStrOrNullMark(itm_val));
sb.AddCharNl();
}
return sb.ToStr();
}
}

View File

@@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2021 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.
@@ -13,6 +13,6 @@ 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.objects.lists;
public interface CompareAble extends Comparable {} // URL:/doc/gplx/CompareAble_.txt
package gplx.types.commons.lists;
public interface CompareAble<T> extends Comparable<T> {} // URL:/doc/gplx/CompareAble_.txt
// public int compareTo(Object obj) {Type comp = (Type)obj; return prop.compareTo(comp.prop);}

View File

@@ -13,7 +13,7 @@ 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.objects.lists;
package gplx.types.commons.lists;
public class CompareAbleUtl {
public static Comparable as_(Object obj) {return obj instanceof Comparable ? (Comparable)obj : null;}
public static int Compare_obj(Object lhs, Object rhs) {return Compare_comp(as_(lhs), as_(rhs));}

View File

@@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2021 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.
@@ -13,7 +13,7 @@ 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.objects.lists;
package gplx.types.commons.lists;
import java.util.Comparator;
public interface ComparerAble extends Comparator {
}

View File

@@ -1,61 +1,61 @@
/*
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.objects.lists;
public class ComparerAbleSorter {
private ComparerAble comparer = null;
public void Sort(Object[] orig, int origLen) {Sort(orig, origLen, true, null);}
public void Sort(Object[] orig, int origLen, boolean asc, ComparerAble comparer) {
this.comparer = comparer;
Object[] temp = new Object[origLen];
MergeSort(asc, orig, temp, 0, origLen - 1);
this.comparer = null;
}
private void MergeSort(boolean asc, Object[] orig, Object[] temp, int lhs, int rhs) {
if (lhs < rhs) {
int mid = (lhs + rhs) / 2;
MergeSort(asc, orig, temp, lhs, mid);
MergeSort(asc, orig, temp, mid + 1, rhs);
Combine(asc, orig, temp, lhs, mid + 1, rhs);
}
}
private void Combine(boolean asc, Object[] orig, Object[] temp, int lhsPos, int rhsPos, int rhsEnd) {
int lhsEnd = rhsPos - 1;
int tmpPos = lhsPos;
int aryLen = rhsEnd - lhsPos + 1;
while (lhsPos <= lhsEnd && rhsPos <= rhsEnd) {
int compareVal = 0;
if (comparer != null)
compareVal = ComparerAbleUtl.Compare(comparer, orig[lhsPos], orig[rhsPos]);
else {
Comparable lhsComp = (Comparable)orig[lhsPos];
compareVal = lhsComp == null ? CompareAbleUtl.Less : lhsComp.compareTo(orig[rhsPos]);
}
if (!asc) compareVal *= -1;
if (compareVal <= CompareAbleUtl.Same) // NOTE: (a) must be < 0; JAVA's String.compareTo returns -number based on position; (b) must be <= else sorting sorted list will change order; EX: sorting (a,1;a,2) on fld0 will switch to (a,2;a,1)
temp[tmpPos++] = orig[lhsPos++];
else
temp[tmpPos++] = orig[rhsPos++];
}
while (lhsPos <= lhsEnd) // Copy rest of first half
temp[tmpPos++] = orig[lhsPos++];
while (rhsPos <= rhsEnd) // Copy rest of right half
temp[tmpPos++] = orig[rhsPos++];
for (int i = 0; i < aryLen; i++, rhsEnd--)
orig[rhsEnd] = temp[rhsEnd];
}
}
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.commons.lists;
public class ComparerAbleSorter {
private ComparerAble comparer = null;
public void Sort(Object[] orig, int origLen) {Sort(orig, origLen, true, null);}
public void Sort(Object[] orig, int origLen, boolean asc, ComparerAble comparer) {
this.comparer = comparer;
Object[] temp = new Object[origLen];
MergeSort(asc, orig, temp, 0, origLen - 1);
this.comparer = null;
}
private void MergeSort(boolean asc, Object[] orig, Object[] temp, int lhs, int rhs) {
if (lhs < rhs) {
int mid = (lhs + rhs) / 2;
MergeSort(asc, orig, temp, lhs, mid);
MergeSort(asc, orig, temp, mid + 1, rhs);
Combine(asc, orig, temp, lhs, mid + 1, rhs);
}
}
private void Combine(boolean asc, Object[] orig, Object[] temp, int lhsPos, int rhsPos, int rhsEnd) {
int lhsEnd = rhsPos - 1;
int tmpPos = lhsPos;
int aryLen = rhsEnd - lhsPos + 1;
while (lhsPos <= lhsEnd && rhsPos <= rhsEnd) {
int compareVal = 0;
if (comparer != null)
compareVal = ComparerAbleUtl.Compare(comparer, orig[lhsPos], orig[rhsPos]);
else {
Comparable lhsComp = (Comparable)orig[lhsPos];
compareVal = lhsComp == null ? CompareAbleUtl.Less : lhsComp.compareTo(orig[rhsPos]);
}
if (!asc) compareVal *= -1;
if (compareVal <= CompareAbleUtl.Same) // NOTE: (a) must be < 0; JAVA's String.compareTo returns -number based on position; (b) must be <= else sorting sorted list will change order; EX: sorting (a,1;a,2) on fld0 will switch to (a,2;a,1)
temp[tmpPos++] = orig[lhsPos++];
else
temp[tmpPos++] = orig[rhsPos++];
}
while (lhsPos <= lhsEnd) // Copy rest of first half
temp[tmpPos++] = orig[lhsPos++];
while (rhsPos <= rhsEnd) // Copy rest of right half
temp[tmpPos++] = orig[rhsPos++];
for (int i = 0; i < aryLen; i++, rhsEnd--)
orig[rhsEnd] = temp[rhsEnd];
}
}

View File

@@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2021 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.
@@ -13,7 +13,7 @@ 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.objects.lists;
package gplx.types.commons.lists;
public class ComparerAbleUtl {
public static int Compare(ComparerAble comparer, Object lhs, Object rhs) {return comparer.compare(lhs, rhs);}
}

View File

@@ -13,6 +13,6 @@ 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.objects.lists;
package gplx.types.commons.lists;
public interface GfoComparator<T> extends java.util.Comparator<T> {
}

View File

@@ -13,8 +13,8 @@ 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.objects.lists;
import gplx.objects.errs.ErrUtl;
package gplx.types.commons.lists;
import gplx.types.errs.ErrUtl;
import java.util.HashMap;
import java.util.Iterator;

View File

@@ -13,7 +13,7 @@ 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.objects.lists;
package gplx.types.commons.lists;
public interface GfoHashKeyFunc<K> {
K ToHashKey();
}

View File

@@ -13,9 +13,9 @@ 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.objects.lists;
import gplx.objects.GfoKeyVal;
import gplx.objects.errs.ErrUtl;
package gplx.types.commons.lists;
import gplx.types.commons.GfoKeyVal;
import gplx.types.errs.ErrUtl;
import java.util.Iterator;
import java.util.Map;

View File

@@ -13,11 +13,10 @@ 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.objects.lists;
import gplx.objects.errs.ErrUtl;
import gplx.objects.events.GfoEvent;
import gplx.objects.events.GfoEventOwner;
package gplx.types.commons.lists;
import gplx.frameworks.events.GfoEvent;
import gplx.frameworks.events.GfoEventOwner;
import gplx.types.errs.ErrUtl;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Iterator;
@@ -35,15 +34,8 @@ public class GfoListBase<E> implements Iterable<E>, GfoEventOwner {
public E GetAtBgn() {return list.get(0);}
public E GetAtEnd() {return list.get(list.size() - 1);}
@Override
public boolean EventsEnabled() {
return eventsEnabled;
}
@Override
public void EventsEnabledSet(boolean v) {
eventsEnabled = v;
}
@Override public boolean EventsEnabled() {return eventsEnabled;}
@Override public void EventsEnabledSet(boolean v) {eventsEnabled = v;}
public GfoEvent<ItemsChangedArg<E>> ItemsChanged() {return itemsChanged;} private final GfoEvent<ItemsChangedArg<E>> itemsChanged;
public GfoListBase<E> Add(E itm) {
list.add(itm);
@@ -124,7 +116,12 @@ public class GfoListBase<E> implements Iterable<E>, GfoEventOwner {
rv[i] = list.get(i);
return rv;
}
public String[] ToStringAry() {
public E[] ToAryAndClear(Class<?> clz) {
E[] ary = ToAry(clz);
this.Clear();
return ary;
}
public String[] ToAryStr() {
int len = list.size();
String[] rv = new String[len];
for (int i = 0; i < len; i++)
@@ -132,11 +129,7 @@ public class GfoListBase<E> implements Iterable<E>, GfoEventOwner {
return rv;
}
@Override
public Iterator<E> iterator() {
return new GfoListBaseIterator(list);
}
@Override public Iterator<E> iterator() {return new GfoListBaseIterator(list);}
class GfoListBaseIterator implements Iterator<E> {
private final List<E> list;
private int curIdx;
@@ -145,19 +138,9 @@ public class GfoListBase<E> implements Iterable<E>, GfoEventOwner {
this.list = list;
this.len = list.size();
}
@Override
public boolean hasNext() {
return curIdx < len;
}
@Override
public E next() {
return (E)list.get(curIdx++);
}
@Override
public void remove() {
throw ErrUtl.NewUnimplemented();
}
@Override public boolean hasNext() {return curIdx < len;}
@Override public E next() {return (E)list.get(curIdx++);}
@Override public void remove() {throw ErrUtl.NewUnimplemented();}
}
public static <E> GfoListBase<E> NewFromArray(E... array) {
@@ -167,4 +150,5 @@ public class GfoListBase<E> implements Iterable<E>, GfoEventOwner {
}
return rv;
}
public static final int Base1 = 1;
}

View File

@@ -13,8 +13,8 @@ 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.objects.lists;
import gplx.objects.errs.ErrUtl;
package gplx.types.commons.lists;
import gplx.types.errs.ErrUtl;
import java.util.HashSet;
import java.util.Iterator;

View File

@@ -13,7 +13,7 @@ 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.objects.lists;
package gplx.types.commons.lists;
public class ItemsChangedArg<T> {
public ItemsChangedArg(ItemsChangedType type, GfoListBase<T> itms) {
this.type = type;

View File

@@ -13,7 +13,7 @@ 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.objects.lists;
package gplx.types.commons.lists;
public enum ItemsChangedType {
Add,
Del,

View File

@@ -13,7 +13,7 @@ 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.objects.lists;
package gplx.types.commons.lists;
import java.util.List;
public class ListUtil {
public static byte[] ToArray(List<Byte> list) {

View File

@@ -0,0 +1,381 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.custom.brys;
import gplx.types.basics.utls.BryLni;
import gplx.types.errs.ErrUtl;
import gplx.types.basics.constants.AsciiByte;
public class BryFind {
public static final int NotFound = -1;
public static int FindFwd(byte[] src, byte lkp) {return FindFwd(src, lkp, 0, src.length);}
public static int FindFwd(byte[] src, byte lkp, int cur) {return FindFwd(src, lkp, cur, src.length);}
public static int FindFwd(byte[] src, byte[] lkp) {return Find(src, lkp, 0 , src.length, true);}
public static int FindFwd(byte[] src, byte[] lkp, int cur) {return Find(src, lkp, cur , src.length, true);}
public static int FindFwd(byte[] src, byte[] lkp, int cur, int end) {return Find(src, lkp, cur , end, true);}
public static int FindFwd(byte[] src, byte lkp, int cur, int end) {
for (int i = cur; i < end; i++)
if (src[i] == lkp) return i;
return BryFind.NotFound;
}
public static int FindFwdOr(byte[] src, byte lkp, int cur, int end, int or) {
int rv = FindFwd(src, lkp, cur, end);
return rv == BryFind.NotFound ? or : rv;
}
public static int FindFwdOr(byte[] src, byte[] lkp, int cur, int end, int or) {
int rv = FindFwd(src, lkp, cur, end);
return rv == BryFind.NotFound ? or : rv;
}
public static int FindBwd(byte[] src, byte lkp) {return FindBwd(src, lkp, src.length, 0);}
public static int FindBwd(byte[] src, byte lkp, int cur) {return FindBwd(src, lkp, cur , 0);}
public static int FindBwd(byte[] src, byte lkp, int cur, int end) {
--cur; // always subtract 1 from cur; allows passing in src_len or cur_pos without forcing caller to subtract - 1; DATE:2014-02-11
--end;
for (int i = cur; i > end; i--)
if (src[i] == lkp) return i;
return BryFind.NotFound;
}
public static int FindBwdOr(byte[] src, byte lkp, int cur, int end, int or) {
int rv = FindBwd(src, lkp, cur, end);
return rv == BryFind.NotFound ? or : rv;
}
private static final int OffsetCompare = 1;// handle srcPos >= 1 -> srcPosChk > 0
public static int Find(byte[] src, byte[] lkp, int src_bgn, int src_end, boolean fwd) {
if (src_bgn < 0 || src.length == 0) return BryFind.NotFound;
int dif, lkp_len = lkp.length, lkp_bgn, lkp_end, src_end_chk;
if (fwd) {
if (src_bgn > src_end) return BryFind.NotFound;
dif = 1; lkp_bgn = 0; lkp_end = lkp_len; src_end_chk = src_end - OffsetCompare;
}
else {
if (src_bgn < src_end) return BryFind.NotFound;
dif = -1; lkp_bgn = lkp_len - 1; lkp_end = -1; src_end_chk = src.length - OffsetCompare; // src_end_chk needed when going bwd, b/c lkp_len may be > 1
}
while (src_bgn != src_end) { // while src is not done;
int lkp_cur = lkp_bgn;
while (lkp_cur != lkp_end) { // while lkp is not done
int pos = src_bgn + lkp_cur;
if ( pos > src_end_chk // outside bounds; occurs when lkp_len > 1
|| src[pos] != lkp[lkp_cur]) // srcByte doesn't match lkpByte
break;
else
lkp_cur += dif;
}
if (lkp_cur == lkp_end) return src_bgn; // lkp matches src; exit
src_bgn += dif;
}
return BryFind.NotFound;
}
public static int FindBwd(byte[] src, byte[] lkp, int cur) {return FindBwd(src, lkp, cur , 0);}
public static int FindBwd(byte[] src, byte[] lkp, int cur, int end) {
if (cur < 1) return BryFind.NotFound;
--cur; // always subtract 1 from cur; allows passing in src_len or cur_pos without forcing caller to subtract - 1; DATE:2014-02-11
--end;
int src_len = src.length;
int lkp_len = lkp.length;
for (int i = cur; i > end; i--) {
if (i + lkp_len > src_len) continue; // lkp too small for pos; EX: src=abcde; lkp=bcd; pos=4
boolean match = true;
for (int j = 0; j < lkp_len; j++) {
if (lkp[j] != src[i + j]) {
match = false;
break;
}
}
if (match) return i;
}
return BryFind.NotFound;
}
public static int FindBwdLastWs(byte[] src, int cur) {
if (cur < 1) return BryFind.NotFound;
--cur;
int rv = BryFind.NotFound;
for (int i = cur; i > -1; i--) {
byte b = src[i];
switch (b) {
case AsciiByte.Space: case AsciiByte.Tab: case AsciiByte.Nl: case AsciiByte.Cr:
rv = i;
break;
default:
i = -1;
break;
}
}
return rv;
}
public static int FindBwdWs(byte[] src, int cur, int end) {
for (int i = cur; i > -1; --i) {
byte b = src[i];
switch (b) {
case AsciiByte.Space: case AsciiByte.Tab: case AsciiByte.Nl: case AsciiByte.Cr:
return i;
}
}
return BryFind.NotFound;
}
public static int FindBwdNonWsOrNotFound(byte[] src, int cur, int end) { // get pos of 1st char that is not ws;
if (cur >= src.length) return BryFind.NotFound;
for (int i = cur; i >= end; i--) {
byte b = src[i];
switch (b) {
case AsciiByte.Space: case AsciiByte.Tab: case AsciiByte.Nl: case AsciiByte.Cr:
break;
default:
return i;
}
}
return BryFind.NotFound;
}
public static int FindBwdWhileSpaceOrTab(byte[] src, int cur, int end) { // get pos of 1st char that is not \t or \s
if (cur < 0 || cur > src.length) return BryFind.NotFound;
for (int i = cur - 1; i >= end; i--) {
byte b = src[i];
switch (b) {
case AsciiByte.Space: case AsciiByte.Tab:
break;
default:
return i + 1;
}
}
return BryFind.NotFound;
}
public static int FindBwdSkipWs(byte[] src, int end, int bgn) {
int src_len = src.length;
if (end == src_len) return end;
if (end > src_len || end < 0) return BryFind.NotFound;
int pos = end - 1; // start from end - 1; handles situations where len is passed in
for (int i = pos; i >= bgn; --i) {
switch (src[i]) {
case AsciiByte.Space: case AsciiByte.Tab: case AsciiByte.Nl: case AsciiByte.Cr:
break;
default:
return i + 1;
}
}
return bgn;
}
public static int FindBwdSkip(byte[] src, int end, int bgn, byte skip) {
int src_len = src.length; // if (end == src_len) return end;
if (end > src_len || end < 0) return BryFind.NotFound;
int pos = end - 1; // start from end - 1; handles situations where len is passed in
for (int i = pos; i >= bgn; --i) {
if (src[i] != skip)
return i + 1;
}
return bgn;
}
public static int FindBwdSkip(byte[] src, int end, int bgn, byte[] skip) {
int src_len = src.length;
if (end > src_len || end < 0) return BryFind.NotFound;
int skip_len = skip.length;
int pos = end - skip_len; // start from end - 1; handles situations where len is passed in
for (int i = pos; i >= bgn; --i) {
if (!BryLni.Eq(src, i, i + skip_len, skip))
return i + skip_len;
}
return bgn;
}
public static int FindBwdWhile(byte[] src, int cur, int end, byte while_byte) {
--cur;
while (true) {
if ( cur < end
|| src[cur] != while_byte) return cur;
--cur;
}
}
public static int FindBwdWhileIn(byte[] src, int cur, int end, boolean[] while_ary) {
while (true) {
if (cur <= end || !while_ary[src[cur]]) return cur;
cur--;
}
}
public static int FindBwdWhileV2(byte[] src, int cur, int end, byte while_byte) {
--cur;
while (true) {
if ( cur < end
|| src[cur] != while_byte) return cur + 1;
--cur;
}
}
public static int FindFwdWhile(byte[] src, int cur, int end, byte while_byte) {
while (true) {
if ( cur == end
|| src[cur] != while_byte) return cur;
cur++;
}
}
public static int FindFwdWhile(byte[] src, int cur, int end, byte[] while_bry) {
int while_len = while_bry.length;
while (true) {
if (cur == end) return cur;
for (int i = 0; i < while_len; i++) {
if (while_bry[i] != src[i + cur]) return cur;
}
cur += while_len;
}
}
public static int FindFwdWhileIn(byte[] src, int cur, int end, boolean[] while_ary) {
while (cur < end) {
if (cur == end || !while_ary[src[cur]]) return cur;
cur++;
}
return end;
}
public static boolean[] FindFwdWhileInGen(byte... ary) {
boolean[] rv = new boolean[256];
int len = ary.length;
for (int i = 0; i < len; i++) {
rv[ary[i]] = true;
}
return rv;
}
public static int FindFwdUntil(byte[] src, int cur, int end, byte until_byte) {
while (true) {
if ( cur == end
|| src[cur] == until_byte) return cur;
cur++;
}
}
public static int FindFwdUntilWs(byte[] src, int cur, int end) {
while (true) {
if (cur == end) return BryFind.NotFound;
switch (src[cur]) {
case AsciiByte.Space: case AsciiByte.Tab: case AsciiByte.Nl: case AsciiByte.Cr:
return cur;
default:
++cur;
break;
}
}
}
public static int FindFwdWhileSpaceOrTab(byte[] src, int cur, int end) {
while (true) {
if (cur == end) return cur;
switch (src[cur]) {
case AsciiByte.Space: case AsciiByte.Tab: ++cur; break;
default: return cur;
}
}
}
public static int TrimFwdSpaceTab(byte[] src, int cur, int end) {
while (true) {
if (cur == end) return cur;
switch (src[cur]) {
case AsciiByte.Space: case AsciiByte.Tab: ++cur; break;
default: return cur;
}
}
}
public static int TrimBwdSpaceTab(byte[] src, int cur, int bgn) {
while (true) {
int prv_cur = cur - 1; // check byte before cur; EX: "a b " will have len of 4, and pass cur=4;
if (prv_cur < bgn) return cur; // checking byte before prv; exit;
switch (src[prv_cur]) {
case AsciiByte.Space: case AsciiByte.Tab: --cur; break;
default: return cur;
}
}
}
public static int FindFwdWhileWs(byte[] src, int cur, int end) {
while (true) {
if (cur == end) return cur;
try {
switch (src[cur]) {
case AsciiByte.Nl: case AsciiByte.Cr:
case AsciiByte.Space: case AsciiByte.Tab: ++cur; break;
default: return cur;
}
} catch (Exception e) {throw ErrUtl.NewArgs(e, "idx is invalid", "cur", cur, "src", src);}
}
}
public static int FindFwdWhileLetter(byte[] src, int cur, int end) {
while (cur < end) {
switch (src[cur]) {
case AsciiByte.Ltr_A: case AsciiByte.Ltr_B: case AsciiByte.Ltr_C: case AsciiByte.Ltr_D: case AsciiByte.Ltr_E:
case AsciiByte.Ltr_F: case AsciiByte.Ltr_G: case AsciiByte.Ltr_H: case AsciiByte.Ltr_I: case AsciiByte.Ltr_J:
case AsciiByte.Ltr_K: case AsciiByte.Ltr_L: case AsciiByte.Ltr_M: case AsciiByte.Ltr_N: case AsciiByte.Ltr_O:
case AsciiByte.Ltr_P: case AsciiByte.Ltr_Q: case AsciiByte.Ltr_R: case AsciiByte.Ltr_S: case AsciiByte.Ltr_T:
case AsciiByte.Ltr_U: case AsciiByte.Ltr_V: case AsciiByte.Ltr_W: case AsciiByte.Ltr_X: case AsciiByte.Ltr_Y: case AsciiByte.Ltr_Z:
case AsciiByte.Ltr_a: case AsciiByte.Ltr_b: case AsciiByte.Ltr_c: case AsciiByte.Ltr_d: case AsciiByte.Ltr_e:
case AsciiByte.Ltr_f: case AsciiByte.Ltr_g: case AsciiByte.Ltr_h: case AsciiByte.Ltr_i: case AsciiByte.Ltr_j:
case AsciiByte.Ltr_k: case AsciiByte.Ltr_l: case AsciiByte.Ltr_m: case AsciiByte.Ltr_n: case AsciiByte.Ltr_o:
case AsciiByte.Ltr_p: case AsciiByte.Ltr_q: case AsciiByte.Ltr_r: case AsciiByte.Ltr_s: case AsciiByte.Ltr_t:
case AsciiByte.Ltr_u: case AsciiByte.Ltr_v: case AsciiByte.Ltr_w: case AsciiByte.Ltr_x: case AsciiByte.Ltr_y: case AsciiByte.Ltr_z:
break;
default:
return cur;
}
++cur;
}
return cur;
}
public static int FindFwdWhileNum(byte[] src, int cur, int end) {
while (cur < end) {
if (!AsciiByte.IsNum(src[cur]))
return cur;
++cur;
}
return cur;
}
public static int FindFwdWhileNotWs(byte[] src, int cur, int end) {
while (true) {
if (cur == end) return cur;
switch (src[cur]) {
case AsciiByte.Space:
case AsciiByte.Nl:
case AsciiByte.Tab:
case AsciiByte.Cr:
++cur;
break;
default:
return cur;
}
}
}
public static int FindBwdWhileAlphanum(byte[] src, int cur) {return FindBwdWhileAlphanum(src, cur, -1);}
public static int FindBwdWhileAlphanum(byte[] src, int cur, int end) {
--cur;
while (cur > end) {
switch (src[cur]) {
case AsciiByte.Num0: case AsciiByte.Num1: case AsciiByte.Num2: case AsciiByte.Num3: case AsciiByte.Num4:
case AsciiByte.Num5: case AsciiByte.Num6: case AsciiByte.Num7: case AsciiByte.Num8: case AsciiByte.Num9:
case AsciiByte.Ltr_A: case AsciiByte.Ltr_B: case AsciiByte.Ltr_C: case AsciiByte.Ltr_D: case AsciiByte.Ltr_E:
case AsciiByte.Ltr_F: case AsciiByte.Ltr_G: case AsciiByte.Ltr_H: case AsciiByte.Ltr_I: case AsciiByte.Ltr_J:
case AsciiByte.Ltr_K: case AsciiByte.Ltr_L: case AsciiByte.Ltr_M: case AsciiByte.Ltr_N: case AsciiByte.Ltr_O:
case AsciiByte.Ltr_P: case AsciiByte.Ltr_Q: case AsciiByte.Ltr_R: case AsciiByte.Ltr_S: case AsciiByte.Ltr_T:
case AsciiByte.Ltr_U: case AsciiByte.Ltr_V: case AsciiByte.Ltr_W: case AsciiByte.Ltr_X: case AsciiByte.Ltr_Y: case AsciiByte.Ltr_Z:
case AsciiByte.Ltr_a: case AsciiByte.Ltr_b: case AsciiByte.Ltr_c: case AsciiByte.Ltr_d: case AsciiByte.Ltr_e:
case AsciiByte.Ltr_f: case AsciiByte.Ltr_g: case AsciiByte.Ltr_h: case AsciiByte.Ltr_i: case AsciiByte.Ltr_j:
case AsciiByte.Ltr_k: case AsciiByte.Ltr_l: case AsciiByte.Ltr_m: case AsciiByte.Ltr_n: case AsciiByte.Ltr_o:
case AsciiByte.Ltr_p: case AsciiByte.Ltr_q: case AsciiByte.Ltr_r: case AsciiByte.Ltr_s: case AsciiByte.Ltr_t:
case AsciiByte.Ltr_u: case AsciiByte.Ltr_v: case AsciiByte.Ltr_w: case AsciiByte.Ltr_x: case AsciiByte.Ltr_y: case AsciiByte.Ltr_z:
--cur;
break;
default:
return cur;
}
}
return 0; // always return a valid index
}
public static int MoveFwd(byte[] src, byte lkp, int cur, int end) {
int rv = FindFwd(src, lkp, cur, src.length);
return rv == BryFind.NotFound ? rv : rv + 1;
}
public static int MoveFwd(byte[] src, byte[] lkp, int cur) {return MoveFwd(src, lkp, cur, src.length);}
public static int MoveFwd(byte[] src, byte[] lkp, int cur, int end) {
int rv = FindFwd(src, lkp, cur, src.length);
return rv == BryFind.NotFound ? rv : rv + lkp.length;
}
}

View File

@@ -0,0 +1,177 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.custom.brys;
import gplx.types.commons.lists.GfoListBase;
import gplx.types.basics.constants.AsciiByte;
import gplx.types.basics.utls.BryLni;
import gplx.types.basics.utls.BryUtl;
import gplx.types.errs.ErrUtl;
public class BrySplit {
private static final Object thread_lock = new Object();
public static byte[][] Split(byte[] src, byte dlm) {return Split(src, dlm, false);}
public static byte[][] Split(byte[] src, byte dlm, boolean trim) {return src == null ? BryUtl.AryEmpty : Split(src, 0, src.length, dlm, trim);}
public static byte[][] Split(byte[] src, int bgn, int end, byte dlm, boolean trim) {
synchronized (thread_lock) {
BrySplitWkrAry wkr = BrySplitWkrAry.Instance;
Split(src, bgn, end, dlm, trim, wkr);
return wkr.ToAry();
}
}
public static int Split(byte[] src, int src_bgn, int src_end, byte dlm, boolean trim, BrySplitWkr wkr) {
if (src == null || src_end - src_bgn < 1) return 0;
int pos = src_bgn;
int itm_bgn = -1, itm_end = -1;
int count = 0;
while (true) {
boolean pos_is_last = pos == src_end;
byte b = pos_is_last ? dlm : src[pos];
int nxt_pos = pos + 1;
boolean process = true;
switch (b) {
case AsciiByte.Space: case AsciiByte.Tab: case AsciiByte.Nl: case AsciiByte.Cr: // ignore ws; assumes that flags have no ws (they are single char) and vnts have no ws (EX: zh-hans)
if (trim && b != dlm) process = false; // b != dlm handles cases where ws is dlm, but trim is enabled; EX: " a \n b" -> "a", "b"
break;
}
if (process) {
if (b == dlm) {
boolean reset = true;
if (itm_bgn == -1) {
if (pos_is_last) {} // skip dlm at bgn / end; EX: "a,"
else {wkr.Split(src, pos, pos );} // else, process "empty" dlm; EX: ",a"
}
else {
int rv = wkr.Split(src, itm_bgn, itm_end);
switch (rv) {
case Rv__ok: ++count; break;
case Rv__extend: reset = false; break;
case Rv__cancel: return count;
default: throw ErrUtl.NewUnhandled(rv);
}
}
if (reset) itm_bgn = itm_end = -1;
}
else {
if (itm_bgn == -1) itm_bgn = pos;
itm_end = nxt_pos;
}
}
if (pos_is_last) break;
pos = nxt_pos;
}
return count;
}
public static byte[][] Split(byte[] src, byte[] dlm) {return Split(src, 0, src.length, dlm);}
public static byte[][] Split(byte[] src, int src_bgn, int src_end, byte[] dlm) {
if (src == null) return BryUtl.AryEmpty;
int src_len = src.length;
if (src_len == 0) return BryUtl.AryEmpty;
int cur_pos = src_bgn, dlm_len = dlm.length;
GfoListBase<byte[]> rv = new GfoListBase<>();
while (true) {
int find_pos = BryFind.FindFwd(src, dlm, cur_pos);
if (find_pos == BryFind.NotFound) {
if (cur_pos >= src_end) break; // dlm is last sequence in src; do not create empty itm
find_pos = src_end;
}
rv.Add(BryLni.Mid(src, cur_pos, find_pos));
cur_pos = find_pos + dlm_len;
if (cur_pos >= src_end) break;
}
return rv.ToAry(byte[].class);
}
public static byte[][] SplitLines(byte[] src) {
if (BryUtl.IsNullOrEmpty(src)) return BryUtl.AryEmpty;
int src_len = src.length, src_pos = 0, fld_bgn = 0;
GfoListBase<byte[]> rv = new GfoListBase<>();
while (true) {
boolean last = src_pos == src_len;
byte b = last ? AsciiByte.Nl : src[src_pos];
int nxt_bgn = src_pos + 1;
switch (b) {
case AsciiByte.Cr:
case AsciiByte.Nl:
if ( b == AsciiByte.Cr // check for crlf
&& nxt_bgn < src_len && src[nxt_bgn] == AsciiByte.Nl) {
++nxt_bgn;
}
if (last && (src_pos - fld_bgn == 0)) {} // ignore trailing itms
else
rv.Add(BryLni.Mid(src, fld_bgn, src_pos));
fld_bgn = nxt_bgn;
break;
}
if (last) break;
src_pos = nxt_bgn;
}
return rv.ToAry(byte[].class);
}
public static byte[][] SplitWithmax(byte[] src, byte dlm, int max) {
byte[][] rv = new byte[max][];
int src_len = src.length;
int rv_idx = 0;
int itm_bgn = 0;
int src_pos = 0;
while (true) {
boolean is_last = src_pos == src_len;
byte b = is_last ? dlm : src[src_pos];
if (b == dlm) {
rv[rv_idx++] = BryLni.Mid(src, itm_bgn, src_pos);
itm_bgn = src_pos + 1;
}
if (is_last || rv_idx == max)
break;
else
src_pos++;
}
return rv;
}
public static byte[][] SplitWs(byte[] src) {// REF.PHP: preg_split('/\s+/', $text)
int len = src.length;
if (len == 0) return BryUtl.AryEmpty;
GfoListBase<byte[]> list = new GfoListBase<>();
int pos = 0;
while (true) {
int bgn = BryFind.FindFwdWhileWs(src, pos, len);
if (bgn == len) break; // EOS
int end = BryFind.FindFwdUntilWs(src, bgn + 1, len);
if (end == -1) end = len;
list.Add(BryLni.Mid(src, bgn, end));
pos = end + 1;
if (pos >= len) break;
}
return list.ToAry(byte[].class);
}
public static final int Rv__ok = 0, Rv__extend = 1, Rv__cancel = 2;
}
class BrySplitWkrAry implements BrySplitWkr {
private final GfoListBase<byte[]> list = new GfoListBase<>();
public int Split(byte[] src, int itm_bgn, int itm_end) {
synchronized (list) {
byte[] bry = itm_end == itm_bgn ? BryUtl.Empty : BryLni.Mid(src, itm_bgn, itm_end);
list.Add(bry);
return BrySplit.Rv__ok;
}
}
public byte[][] ToAry() {
synchronized (list) {
return list.ToAryAndClear(byte[].class);
}
}
public static final BrySplitWkrAry Instance = new BrySplitWkrAry(); BrySplitWkrAry() {}
}

View File

@@ -0,0 +1,19 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.custom.brys;
public interface BrySplitWkr {
int Split(byte[] src, int itm_bgn, int itm_end);
}

View File

@@ -0,0 +1,96 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2021 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.types.custom.brys;
import gplx.types.basics.utls.BryLni;
import gplx.types.basics.utls.BryUtl;
import gplx.types.commons.lists.GfoListBase;
import gplx.types.basics.constants.AsciiByte;
import gplx.frameworks.tests.GfoTstr;
import gplx.types.basics.utls.BoolUtl;
import gplx.types.basics.utls.StringUtl;
import org.junit.Test;
public class BrySplitWkrTest {
private final BrySplitWkrTstr tstr = new BrySplitWkrTstr();
@Test public void Split() {
tstr.TestSplit("a" , AsciiByte.Pipe, BoolUtl.N, "a"); // no trim
tstr.TestSplit("a|" , AsciiByte.Pipe, BoolUtl.N, "a");
tstr.TestSplit("|a" , AsciiByte.Pipe, BoolUtl.N, "", "a");
tstr.TestSplit("|" , AsciiByte.Pipe, BoolUtl.N, "");
tstr.TestSplit("" , AsciiByte.Pipe, BoolUtl.N);
tstr.TestSplit("a|b|c" , AsciiByte.Pipe, BoolUtl.N, "a", "b", "c");
tstr.TestSplit(" a " , AsciiByte.Pipe, BoolUtl.Y, "a"); // trim
tstr.TestSplit(" a |" , AsciiByte.Pipe, BoolUtl.Y, "a");
tstr.TestSplit("| a " , AsciiByte.Pipe, BoolUtl.Y, "", "a");
tstr.TestSplit(" | " , AsciiByte.Pipe, BoolUtl.Y, "");
tstr.TestSplit(" " , AsciiByte.Pipe, BoolUtl.Y);
tstr.TestSplit(" a | b | c " , AsciiByte.Pipe, BoolUtl.Y, "a", "b", "c");
tstr.TestSplit(" a b | c d " , AsciiByte.Pipe, BoolUtl.Y, "a b", "c d");
tstr.TestSplit(" a \n b " , AsciiByte.Nl , BoolUtl.N, " a ", " b "); // ws as dlm
tstr.TestSplit(" a \n b " , AsciiByte.Nl , BoolUtl.Y, "a", "b"); // ws as dlm; trim
tstr.TestSplit("a|extend|b" , AsciiByte.Pipe, BoolUtl.Y, "a", "extend|b"); // extend
tstr.TestSplit("extend|a" , AsciiByte.Pipe, BoolUtl.Y, "extend|a"); // extend
tstr.TestSplit("a|cancel|b" , AsciiByte.Pipe, BoolUtl.Y, "a"); // cancel
}
@Test public void SplitBry() {
tstr.TestSplit("a|b|c|d" , 2, 6, "|", "b", "c");
tstr.TestSplit("a|b|c|d" , 2, 4, "|", "b");
}
@Test public void Empty() {
tstr.TestSplit("a\n\nb" , AsciiByte.Nl, BoolUtl.N, "a", "", "b");
}
@Test public void SplitWithMax() {
tstr.TestSplitWithMax("a|b|c|d" , AsciiByte.Pipe, 2, "a", "b"); // max is less
tstr.TestSplitWithMax("a" , AsciiByte.Pipe, 2, "a", null); // max is more
tstr.TestSplitWithMax("|" , AsciiByte.Pipe, 2, "", ""); // empty itms
}
@Test public void SplitWs() {
tstr.TestSplitWs("a b", "a", "b");
tstr.TestSplitWs(" a ", "a");
tstr.TestSplitWs(" abc def ", "abc", "def");
}
}
class BrySplitWkrTstr {
private final BrySplitWkrExample wkr = new BrySplitWkrExample();
public void TestSplit(String raw_str, byte dlm, boolean trim, String... expd) {
byte[] src = BryUtl.NewA7(raw_str);
BrySplit.Split(src, 0, src.length, dlm, trim, wkr);
byte[][] actl_ary = wkr.ToAry();
GfoTstr.EqLines(expd, StringUtl.Ary(actl_ary));
}
public void TestSplit(String src, int src_bgn, int src_end, String dlm, String... expd) {
GfoTstr.EqLines(BryUtl.Ary(expd), BrySplit.Split(BryUtl.NewU8(src), src_bgn, src_end, BryUtl.NewU8(dlm)));
}
public void TestSplitWithMax(String src, byte dlm, int max, String... expd) {
GfoTstr.EqLines(expd, StringUtl.Ary(BrySplit.SplitWithmax(BryUtl.NewU8(src), dlm, max)));
}
public void TestSplitWs(String raw, String... expd) {
byte[][] actl = BrySplit.SplitWs(BryUtl.NewU8(raw));
GfoTstr.EqLines(BryUtl.Ary(expd), actl, raw);
}
}
class BrySplitWkrExample implements BrySplitWkr {
private final GfoListBase<byte[]> list = new GfoListBase<>();
public int Split(byte[] src, int itm_bgn, int itm_end) {
byte[] bry = itm_end == itm_bgn ? BryUtl.Empty : BryLni.Mid(src, itm_bgn, itm_end);
if (BryLni.Eq(bry, BryUtl.NewA7("extend"))) return BrySplit.Rv__extend;
else if (BryLni.Eq(bry, BryUtl.NewA7("cancel"))) return BrySplit.Rv__cancel;
list.Add(bry);
return BrySplit.Rv__ok;
}
public byte[][] ToAry() {
return list.ToAryAndClear(byte[].class);
}
}

Some files were not shown because too many files have changed in this diff Show More