|
|
/*
|
|
|
XOWA: the XOWA Offline Wiki Application
|
|
|
Copyright (C) 2012-2017 gnosygnu@gmail.com
|
|
|
|
|
|
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
|
|
|
or alternatively under the terms of the Apache License Version 2.0.
|
|
|
|
|
|
You may use XOWA according to either of these licenses as is most appropriate
|
|
|
for your project on a case-by-case basis.
|
|
|
|
|
|
The terms of each license can be found in the source code repository:
|
|
|
|
|
|
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
|
|
|
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
|
|
|
*/
|
|
|
package gplx;
|
|
|
import gplx.core.primitives.*;
|
|
|
import gplx.core.intls.*;
|
|
|
public class Hash_adp_bry extends gplx.core.lists.Hash_adp_base implements Hash_adp {
|
|
|
private final Hash_adp_bry_itm_base proto, key_ref;
|
|
|
Hash_adp_bry(Hash_adp_bry_itm_base proto) {
|
|
|
this.proto = proto;
|
|
|
this.key_ref = proto.New();
|
|
|
}
|
|
|
@Override protected Object Fetch_base(Object key) {synchronized (key_ref) {return super.Fetch_base(key_ref.Init((byte[])key));}} // TS: DATE:2016-07-06
|
|
|
@Override protected void Del_base(Object key) {synchronized (key_ref) {super.Del_base(key_ref.Init((byte[])key));}}// TS: DATE:2016-07-06
|
|
|
@Override protected boolean Has_base(Object key) {synchronized (key_ref) {return super.Has_base(key_ref.Init((byte[])key));}}// TS: DATE:2016-07-06
|
|
|
public int Get_as_int(byte[] key) {return Get_as_int(key, 0, key.length);}
|
|
|
public int Get_as_int(byte[] key, int bgn, int end) {
|
|
|
int rv = Get_as_int_or(key, bgn, end, Int_.Min_value); if (rv == Int_.Min_value) throw Err_.new_("core", "unknown key", "key", key);
|
|
|
return rv;
|
|
|
}
|
|
|
public int Get_as_int_or(byte[] key, int or) {return Get_as_int_or(key, 0, key.length, or);}
|
|
|
public int Get_as_int_or(byte[] key, int bgn, int end, int or) {
|
|
|
Object o = Get_by_mid(key, bgn, end);
|
|
|
return (o == null) ? or : ((Int_obj_val)o).Val();
|
|
|
}
|
|
|
public byte Get_as_byte_or(byte[] key, byte or) {return Get_as_byte_or(key, 0, key.length, or);}
|
|
|
public byte Get_as_byte_or(byte[] key, int bgn, int end, byte or) {
|
|
|
Object o = Get_by_mid(key, bgn, end);
|
|
|
return o == null ? or : ((Byte_obj_val)o).Val();
|
|
|
}
|
|
|
public Object Get_by_bry(byte[] src) {synchronized (key_ref) {return super.Fetch_base(key_ref.Init(src));}} // TS: DATE:2016-07-06
|
|
|
public Object Get_by_mid(byte[] src, int bgn, int end) {synchronized (key_ref) {return super.Fetch_base(key_ref.Init(src, bgn, end));}}// TS: DATE:2016-07-06
|
|
|
public Hash_adp_bry Add_byte_int(byte key, int val) {this.Add_base(new byte[]{key}, new Int_obj_val(val)); return this;}
|
|
|
public Hash_adp_bry Add_bry_byte(byte[] key, byte val) {this.Add_base(key, Byte_obj_val.new_(val)); return this;}
|
|
|
public Hash_adp_bry Add_bry_int(byte[] key, int val) {this.Add_base(key, new Int_obj_val(val)); return this;}
|
|
|
public Hash_adp_bry Add_bry_bry(byte[] key) {this.Add_base(key, key); return this;}
|
|
|
public Hash_adp_bry Add_str_byte(String key, byte val) {this.Add_base(Bry_.new_u8(key), Byte_obj_val.new_(val)); return this;}
|
|
|
public Hash_adp_bry Add_str_int(String key, int val) {this.Add_base(Bry_.new_u8(key), new Int_obj_val(val)); return this;}
|
|
|
public Hash_adp_bry Add_str_obj(String key, Object val) {this.Add_base(Bry_.new_u8(key), val); return this;}
|
|
|
public Hash_adp_bry Add_bry_obj(byte[] key, Object val) {this.Add_base(key, val); return this;}
|
|
|
public Hash_adp_bry Add_many_str(String... ary) {
|
|
|
int ary_len = ary.length;
|
|
|
for (int i = 0; i < ary_len; i++) {
|
|
|
String itm = ary[i];
|
|
|
byte[] bry = Bry_.new_u8(itm);
|
|
|
Add_bry_bry(bry);
|
|
|
}
|
|
|
return this;
|
|
|
}
|
|
|
public Hash_adp_bry Add_many_bry(byte[]... ary) {
|
|
|
int ary_len = ary.length;
|
|
|
for (int i = 0; i < ary_len; i++)
|
|
|
Add_bry_bry(ary[i]);
|
|
|
return this;
|
|
|
}
|
|
|
@Override protected void Add_base(Object key, Object val) {
|
|
|
byte[] key_bry = (byte[])key;
|
|
|
Hash_adp_bry_itm_base key_itm = proto.New();
|
|
|
key_itm.Init(key_bry, 0, key_bry.length);
|
|
|
super.Add_base(key_itm, val);
|
|
|
}
|
|
|
public static Hash_adp_bry cs() {return new Hash_adp_bry(Hash_adp_bry_itm_cs.Instance);}
|
|
|
public static Hash_adp_bry ci_a7() {return new Hash_adp_bry(Hash_adp_bry_itm_ci_a7.Instance);}
|
|
|
public static Hash_adp_bry ci_u8(Gfo_case_mgr case_mgr) {return new Hash_adp_bry(Hash_adp_bry_itm_ci_u8.get_or_new(case_mgr));}
|
|
|
public static Hash_adp_bry c__u8(boolean case_match, Gfo_case_mgr case_mgr) {return case_match ? cs() : ci_u8(case_mgr);}
|
|
|
}
|
|
|
abstract class Hash_adp_bry_itm_base {
|
|
|
public abstract Hash_adp_bry_itm_base New();
|
|
|
public Hash_adp_bry_itm_base Init(byte[] src) {return this.Init(src, 0, src.length);}
|
|
|
public abstract Hash_adp_bry_itm_base Init(byte[] src, int src_bgn, int src_end);
|
|
|
}
|
|
|
class Hash_adp_bry_itm_cs extends Hash_adp_bry_itm_base {
|
|
|
private byte[] src; int src_bgn, src_end;
|
|
|
@Override public Hash_adp_bry_itm_base New() {return new Hash_adp_bry_itm_cs();}
|
|
|
@Override public Hash_adp_bry_itm_base Init(byte[] src, int src_bgn, int src_end) {this.src = src; this.src_bgn = src_bgn; this.src_end = src_end; return this;}
|
|
|
@Override public int hashCode() {
|
|
|
int rv = 0;
|
|
|
for (int i = src_bgn; i < src_end; i++) {
|
|
|
int b_int = src[i] & 0xFF; // JAVA: patch
|
|
|
rv = (31 * rv) + b_int;
|
|
|
}
|
|
|
return rv;
|
|
|
}
|
|
|
@Override public boolean equals(Object obj) {
|
|
|
if (obj == null) return false;
|
|
|
Hash_adp_bry_itm_cs comp = (Hash_adp_bry_itm_cs)obj;
|
|
|
byte[] comp_src = comp.src; int comp_bgn = comp.src_bgn, comp_end = comp.src_end;
|
|
|
int comp_len = comp_end - comp_bgn, src_len = src_end - src_bgn;
|
|
|
if (comp_len != src_len) return false;
|
|
|
for (int i = 0; i < comp_len; i++) {
|
|
|
int src_pos = src_bgn + i;
|
|
|
if (src_pos >= src_end) return false; // ran out of src; exit; EX: src=ab; find=abc
|
|
|
if (src[src_pos] != comp_src[i + comp_bgn]) return false;
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
public static final Hash_adp_bry_itm_cs Instance = new Hash_adp_bry_itm_cs(); Hash_adp_bry_itm_cs() {}
|
|
|
}
|
|
|
class Hash_adp_bry_itm_ci_a7 extends Hash_adp_bry_itm_base {
|
|
|
private byte[] src; int src_bgn, src_end;
|
|
|
@Override public Hash_adp_bry_itm_base New() {return new Hash_adp_bry_itm_ci_a7();}
|
|
|
@Override public Hash_adp_bry_itm_base Init(byte[] src, int src_bgn, int src_end) {this.src = src; this.src_bgn = src_bgn; this.src_end = src_end; return this;}
|
|
|
@Override public int hashCode() {
|
|
|
int rv = 0;
|
|
|
for (int i = src_bgn; i < src_end; i++) {
|
|
|
int b_int = src[i] & 0xFF; // JAVA: patch
|
|
|
if (b_int > 64 && b_int < 91) // 64=before A; 91=after Z; NOTE: lowering upper-case on PERF assumption that there will be more lower-case letters than upper-case
|
|
|
b_int += 32;
|
|
|
rv = (31 * rv) + b_int;
|
|
|
}
|
|
|
return rv;
|
|
|
}
|
|
|
@Override public boolean equals(Object obj) {
|
|
|
if (obj == null) return false;
|
|
|
Hash_adp_bry_itm_ci_a7 comp = (Hash_adp_bry_itm_ci_a7)obj;
|
|
|
byte[] comp_src = comp.src; int comp_bgn = comp.src_bgn, comp_end = comp.src_end;
|
|
|
int comp_len = comp_end - comp_bgn, src_len = src_end - src_bgn;
|
|
|
if (comp_len != src_len) return false;
|
|
|
for (int i = 0; i < comp_len; i++) {
|
|
|
int src_pos = src_bgn + i;
|
|
|
if (src_pos >= src_end) return false; // ran out of src; exit; EX: src=ab; find=abc
|
|
|
byte src_byte = src[src_pos];
|
|
|
if (src_byte > 64 && src_byte < 91) src_byte += 32;
|
|
|
byte comp_byte = comp_src[i + comp_bgn];
|
|
|
if (comp_byte > 64 && comp_byte < 91) comp_byte += 32;
|
|
|
if (src_byte != comp_byte) return false;
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
public static final Hash_adp_bry_itm_ci_a7 Instance = new Hash_adp_bry_itm_ci_a7(); Hash_adp_bry_itm_ci_a7() {}
|
|
|
}
|
|
|
class Hash_adp_bry_itm_ci_u8 extends Hash_adp_bry_itm_base {
|
|
|
private final Gfo_case_mgr case_mgr;
|
|
|
Hash_adp_bry_itm_ci_u8(Gfo_case_mgr case_mgr) {this.case_mgr = case_mgr;}
|
|
|
private byte[] src; int src_bgn, src_end;
|
|
|
@Override public Hash_adp_bry_itm_base New() {return new Hash_adp_bry_itm_ci_u8(case_mgr);}
|
|
|
@Override public Hash_adp_bry_itm_base Init(byte[] src, int src_bgn, int src_end) {this.src = src; this.src_bgn = src_bgn; this.src_end = src_end; return this;}
|
|
|
@Override public int hashCode() {
|
|
|
int rv = 0;
|
|
|
for (int i = src_bgn; i < src_end; i++) {
|
|
|
byte b = src[i];
|
|
|
int b_int = b & 0xFF; // JAVA: patch
|
|
|
Gfo_case_itm itm = case_mgr.Get_or_null(b, src, i, src_end);
|
|
|
if (itm == null) { // unknown itm; byte is a number, symbol, or unknown; just use the existing byte
|
|
|
}
|
|
|
else { // known itm; use its hash_code
|
|
|
b_int = itm.Hashcode_lo();
|
|
|
int b_len = Utf8_.Len_of_char_by_1st_byte(b); // NOTE: must calc b_len for langs with asymmetric upper / lower; PAGE:tr.w:Zvishavane DATE:2015-09-07
|
|
|
i += b_len - 1;
|
|
|
}
|
|
|
rv = (31 * rv) + b_int;
|
|
|
}
|
|
|
return rv;
|
|
|
}
|
|
|
@Override public boolean equals(Object obj) {
|
|
|
if (obj == null) return false;
|
|
|
Hash_adp_bry_itm_ci_u8 trg_itm = (Hash_adp_bry_itm_ci_u8)obj;
|
|
|
byte[] trg = trg_itm.src; int trg_bgn = trg_itm.src_bgn, trg_end = trg_itm.src_end;
|
|
|
int src_c_bgn = src_bgn;
|
|
|
int trg_c_bgn = trg_bgn;
|
|
|
while ( src_c_bgn < src_end
|
|
|
&& trg_c_bgn < trg_end) { // exit once one goes out of bounds
|
|
|
byte src_c = src[src_c_bgn];
|
|
|
byte trg_c = trg[trg_c_bgn];
|
|
|
int src_c_len = Utf8_.Len_of_char_by_1st_byte(src_c);
|
|
|
int trg_c_len = Utf8_.Len_of_char_by_1st_byte(trg_c);
|
|
|
int src_c_end = src_c_bgn + src_c_len;
|
|
|
int trg_c_end = trg_c_bgn + trg_c_len;
|
|
|
Gfo_case_itm src_c_itm = case_mgr.Get_or_null(src_c, src, src_c_bgn, src_c_end);
|
|
|
Gfo_case_itm trg_c_itm = case_mgr.Get_or_null(trg_c, trg, trg_c_bgn, trg_c_end);
|
|
|
if (src_c_itm != null && trg_c_itm == null) return false; // src == ltr; trg != ltr; EX: a, 1
|
|
|
else if (src_c_itm == null && trg_c_itm != null) return false; // src != ltr; trg == ltr; EX: 1, a
|
|
|
else if (src_c_itm == null && trg_c_itm == null) { // src != ltr; trg != ltr; EX: 1, 2; _, Ⓐ
|
|
|
if (!Bry_.Match(src, src_c_bgn, src_c_end, trg, trg_c_bgn, trg_c_end)) return false;// syms do not match; return false;
|
|
|
}
|
|
|
else {
|
|
|
if (src_c_itm.Utf8_id_lo() != trg_c_itm.Utf8_id_lo()) return false; // lower-case utf8-ids don't match; return false; NOTE: using utf8-ids instead of hash-code to handle asymmetric brys; DATE:2015-09-07
|
|
|
}
|
|
|
src_c_bgn = src_c_end;
|
|
|
trg_c_bgn = trg_c_end;
|
|
|
}
|
|
|
return src_c_bgn == src_end && trg_c_bgn == trg_end; // only return true if both src and trg read to end of their brys, otherwise "a","ab" will match
|
|
|
}
|
|
|
public static Hash_adp_bry_itm_ci_u8 get_or_new(Gfo_case_mgr case_mgr) {
|
|
|
switch (case_mgr.Tid()) {
|
|
|
case Gfo_case_mgr_.Tid_a7: if (Itm_a7 == null) Itm_a7 = new Hash_adp_bry_itm_ci_u8(case_mgr); return Itm_a7;
|
|
|
case Gfo_case_mgr_.Tid_u8: if (Itm_u8 == null) Itm_u8 = new Hash_adp_bry_itm_ci_u8(case_mgr); return Itm_u8;
|
|
|
case Gfo_case_mgr_.Tid_custom: return new Hash_adp_bry_itm_ci_u8(case_mgr);
|
|
|
default: throw Err_.new_unhandled(case_mgr.Tid());
|
|
|
}
|
|
|
}
|
|
|
private static Hash_adp_bry_itm_ci_u8 Itm_a7, Itm_u8;
|
|
|
}
|