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

206 lines
11 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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