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/List_adp_base.java

174 lines
6.4 KiB

/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx;
import gplx.core.strings.*; import gplx.core.lists.*;
public abstract class List_adp_base implements List_adp, Gfo_invk {
private Object[] list; private int count;
public List_adp_base(int capacity) {
this.list = new Object[capacity];
}
public java.util.Iterator iterator() {
if (count == 0)
return Iterator_null.Instance;
else
return new Iterator_objAry(list, count);
}
public void Add_many(Object... ary) {for (Object o : ary) Add_base(o);}
public int Len() {return count;}
public int Count() {return count;}
public int Idx_last() {return count - 1;}
protected Object Get_at_base(int index) {if (index >= count || index < 0) throw Err_.new_missing_idx(index, count);
return list[index];
}
protected void Add_base(Object o) {
if (count == Array_.Len_obj(list)) Resize_expand();
list[count] = o;
count++;
}
protected int Del_base(Object o) {
int index = IndexOf_base(o); if (index == List_adp_.Not_found) return List_adp_.Not_found;
this.Del_at(index);
return index;
}
public void Del_range(int delBgn, int delEnd) {
BoundsChk(delBgn, delEnd, count);
if (delBgn == 0 && delEnd == count - 1) { // entire list deleted; call .Clear, else will have 0 elem array
this.Clear();
return;
}
int delLen = (delEnd - delBgn) + 1; // EX: 0,2 creates 3 len ary
int newLen = count - delLen;
Object[] newList = new Object[newLen];
if (delBgn != 0) // copy elements < delBgn; skip if delBgn == 0
Array_.Copy_to(list, 0, newList, 0, delBgn);
if (delEnd != count -1 ) // copy elements > delEnd; skip if delEnd == lastIdx
Array_.Copy_to(list, delEnd + 1, newList, delBgn, newLen - delBgn);
list = newList;
count = list.length;
}
protected int IndexOf_base(Object o) {
for (int i = 0; i < count; i++)
if (Object_.Eq(list[i], o)) return i;
return List_adp_.Not_found;
}
@gplx.Virtual public void Clear() {
for (int i = 0; i < count; i++)
list[i] = null;
count = 0;
}
@gplx.Virtual public void Del_at(int index) {if (index >= count || index < 0) throw Err_.new_missing_idx(index, count);
Collapse(index);
count--;
}
public void Move_to(int src, int trg) {if (src >= count || src < 0) throw Err_.new_missing_idx(src, count); if (trg >= count || trg < 0) throw Err_.new_missing_idx(trg, count);
if (src == trg) return; // position not changed
Object o = list[src];
int dif = trg > src ? 1 : -1;
for (int i = src; i != trg; i += dif)
list[i] = list[i + dif];
list[trg] = o;
}
protected void AddAt_base(int pos, Object o) {
if (count + 1 >= Array_.Len_obj(list)) Resize_expand();
for (int i = count; i > pos; i--)
list[i] = list[i - 1];
list[pos] = o;
count = count + 1;
}
public void Resize_bounds(int i) {
Resize_expand(i);
}
public void Sort() {Sort_by(null);}
public void Sort_by(ComparerAble comparer) {List_adp_sorter.new_().Sort(list, count, true, comparer);}
public void Reverse() {
int mid = count / 2; // no need to reverse pivot; ex: for 3 elements, only 1 and 3 need to be exchanged; 2 stays inplace
for (int lhs = 0; lhs < mid; lhs++) {
int rhs = count - lhs - 1; // -1 b/c list[count] is not real element
Object temp = list[lhs];
list[lhs] = list[rhs];
list[rhs] = temp;
}
}
@gplx.Virtual public void Shuffle() {// REF: Fisher-Yates shuffle
RandomAdp random = RandomAdp_.new_();
for (int i = count; i > 1; i--) {
int rndIdx = random.Next(i);
Object tmp = list[rndIdx];
list[rndIdx] = list[i-1];
list[i-1] = tmp;
}
}
public Object Get_at(int i) {return Get_at_base(i);}
public Object Get_at_last() {if (count == 0) throw Err_.new_invalid_op("cannot call Get_at_last on empty list"); return Get_at_base(count - 1);}
public void Add(Object item) {Add_base(item);}
public void Add_at(int i, Object o) {AddAt_base(i, o);}
public void Del(Object item) {Del_base(item);}
public int Idx_of(Object o) {return IndexOf_base(o);}
public List_adp_base() {
list = new Object[Len_initial];
}
private static final int Len_initial = 8;
public Object To_ary_and_clear(Class<?> memberType) {Object rv = To_ary(memberType); this.Clear(); return rv;}
public Object To_ary(Class<?> memberType) {
Object rv = Array_.Create(memberType, count);
for (int i = 0; i < count; i++)
Array_.Set_at(rv, i, list[i]);
return rv;
}
public String[] To_str_ary_and_clear() {String[] rv = To_str_ary(); this.Clear(); return rv;}
public String[] To_str_ary() {return (String[])To_ary(String.class);}
public Object[] To_obj_ary() {
Object[] rv = new Object[count];
for (int i = 0; i < count; ++i)
rv[i] = list[i];
return rv;
}
public String To_str() {
Bry_bfr bfr = Bry_bfr_.New();
for (int i = 0; i < count; ++i)
bfr.Add_str_u8(Object_.Xto_str_strict_or_null_mark(list[i])).Add_byte_nl();
return bfr.To_str_and_clear();
}
private void BoundsChk(int bgn, int end, int len) {
if ( bgn >= 0 && bgn < len
&& end >= 0 && end < len
&& bgn <= end
) return;
throw Err_.new_wo_type("bounds check failed", "bgn", bgn, "end", end, "len", len);
}
void Resize_expand() {Resize_expand(count * 2);}
void Resize_expand(int newCount) {
Object[] trg = new Object[newCount];
for (int i = 0; i < count; i++) {
trg[i] = list[i];
list[i] = null;
}
list = trg;
}
void Collapse(int index) {
for (int i = index; i < count; i++) {
list[i] = (i == count - 1) ? null : list[i + 1];
}
}
@gplx.Internal protected int Capacity() {return Array_.Len_obj(list);}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_len)) return count;
else if (ctx.Match(k, Invk_get_at)) return Get_at(m.ReadInt("v"));
else return Gfo_invk_.Rv_unhandled;
// return this;
} private static final String Invk_len = "len", Invk_get_at = "get_at";
}