/ *
XOWA: the XOWA Offline Wiki Application
Copyright ( C ) 2012 gnosygnu @gmail.com
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation , either version 3 of the
License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU Affero General Public License for more details .
You should have received a copy of the GNU Affero General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
* /
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 ) { return super . Fetch_base ( key_ref . Init ( ( byte [ ] ) key ) ) ; }
@Override protected void Del_base ( Object key ) { super . Del_base ( key_ref . Init ( ( byte [ ] ) key ) ) ; }
@Override protected boolean Has_base ( Object key ) { return super . Has_base ( key_ref . Init ( ( byte [ ] ) key ) ) ; }
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 ) { return super . Fetch_base ( key_ref . Init ( src ) ) ; }
public Object Get_by_mid ( byte [ ] src , int bgn , int end ) { return super . Fetch_base ( key_ref . Init ( src , bgn , end ) ) ; }
public Hash_adp_bry Add_byte_int ( byte key , int val ) { this . Add_base ( new byte [ ] { key } , Int_obj_val . new_ ( 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 , Int_obj_val . new_ ( 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 ) , Int_obj_val . new_ ( 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 ;
}