All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.reandroid.arsc.base.BlockArray Maven / Gradle / Ivy

There is a newer version: 1.3.5
Show newest version
/*
 *  Copyright (C) 2022 github.com/REAndroid
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.reandroid.arsc.base;

import java.util.*;
import java.util.function.Predicate;


public abstract class BlockArray extends BlockContainer implements BlockArrayCreator  {
    private T[] elementData;
    private int mFreeSpace;
    private int mAllocateStep;
    public BlockArray(){
        elementData = newInstance(0);
    }

    public void removeAllNull(int start){
        removeAll(start, true);
    }
    public void removeAll(int start){
        removeAll(start, false);
    }
    private void removeAll(int start, boolean check_null){
        T[] removeList = subArray(start);
        if(removeList.length == 0 || (check_null && !isAllNull(removeList))){
            return;
        }
        T[] elementData = this.elementData;
        for(T item:removeList){
            if(item == null){
                continue;
            }
            if(!item.isNull()){
                item.setNull(true);
            }
            int index = item.getIndex();
            if(index>=0 && elementData[index]==item){
                item.setIndex(-1);
                item.setParent(null);
                elementData[index] = null;
            }
        }
        setChildesCount(start);
    }
    private T[] subArray(int start){
        return subArray(start, -1);
    }
    private T[] subArray(int start, int count){
        T[] items = this.elementData;
        int length = items.length;
        if(start < 0){
            start = 0;
        }
        if(start >= length){
            return newInstance(0);
        }
        int end = count;
        if(end < 0){
            end = items.length;
        }else {
            end = start + count;
            if(end > length){
                end=length;
            }
        }
        T[] results = newInstance(end - start);
        int index = 0;
        for(int i = start; i < end; i++){
            results[index] = items[i];
            index ++;
        }
        return results;
    }
    public Collection listItems(){
        return listItems(false);
    }
    public Collection listItems(boolean skipNullBlocks){
        trimAllocatedFreeSpace();
        return new AbstractCollection() {
            @Override
            public Iterator iterator(){
                return BlockArray.this.iterator(skipNullBlocks);
            }
            @Override
            public boolean contains(Object o){
                return BlockArray.this.contains(o);
            }
            @Override
            public int size() {
                return BlockArray.this.childesCount();
            }
        };
    }
    @Override
    public T[] getChildes(){
        return elementData;
    }
    public void ensureSize(int size){
        if(size <= childesCount()){
            return;
        }
        setChildesCount(size);
    }
    public void setChildesCount(int count){
        if(count<0){
            count=0;
        }
        if(count==0){
            clearChildes();
            return;
        }
        int diff = count - childesCount();
        if(diff==0){
            return;
        }
        changeSize(diff);
    }
    public void clearChildes(){
        T[] elementData = this.elementData;
        int length = elementData.length;
        if(length == 0){
            return;
        }
        for(int i = 0; i < length; i++){
            T block = elementData[i];
            if(block == null){
                continue;
            }
            block.setIndex(-1);
            block.setParent(null);
            elementData[i]=null;
        }
        this.elementData = newInstance(0);
    }
    public void addAll(T[] blocks){
        if(blocks == null || blocks.length == 0){
            return;
        }
        T[] old = elementData;
        int oldLength = 0;
        if(old != null){
            oldLength = old.length;
        }
        int len = blocks.length;
        T[] update = newInstance(oldLength + len);
        if(oldLength > 0){
            System.arraycopy(old, 0, update, 0, oldLength);
        }
        boolean foundNull=false;
        for(int i=0; i < len; i++){
            T item = blocks[i];
            if(item == null){
                foundNull=true;
                continue;
            }
            int index = oldLength + i;
            update[index]=item;
            item.setParent(this);
            item.setIndex(index);
        }
        elementData = update;
        if(foundNull){
            trimNullBlocks();
        }
    }
    public void sort(Comparator comparator){
        T[] elementData = this.elementData;
        if(comparator == null || elementData.length < 2){
            return;
        }
        Arrays.sort(elementData, 0, elementData.length, comparator);
        for(int i=0 ; i = index; i--){
            T exist = childes[i];
            childes[i] = null;
            int newIndex = i + 1;
            childes[newIndex] = exist;
            exist.setIndex(newIndex);
        }
        childes[index] = item;
        item.setParent(this);
        item.setIndex(index);
    }
    public void setItem(int index, T item){
        ensureSize(index + 1);
        elementData[index] = item;
        if(item != null){
            item.setIndex(index);
            item.setParent(this);
        }
    }
    public void addInternal(int index, T block){
        if(isFlexible()){
            allocateIfFull();
        }else {
            ensureSize(index + 1);
        }
        addAt(index, block);
    }
    private void addAt(int index, T block){
        onPreShifting();
        T[] elementData = this.elementData;
        int start = elementData.length - 1;
        for(int i = start; i > index; i--){
            int left = i - 1;
            T exist = elementData[left];
            elementData[left] = null;
            elementData[i] = exist;
            if(exist != null){
                exist.setIndex(i);
            }
        }
        elementData[index] = block;
        if(block != null){
            block.setIndex(index);
            block.setParent(this);
        }
        onPostShift(index);
        if(isFlexible()){
            mFreeSpace--;
        }
    }
    protected void onPreShifting(){
    }
    protected void onPostShift(int index){
    }
    public void add(T block){
        if(block==null){
            return;
        }
        if(isFlexible()){
            addAtNull(block);
            return;
        }
        T[] old=elementData;
        int index=old.length;
        elementData = newInstance(index+1);
        if(index>0){
            System.arraycopy(old, 0, elementData, 0, index);
        }
        elementData[index]=block;
        block.setIndex(index);
        block.setParent(this);
    }
    private void addAtNull(T block){
        allocateIfFull();
        T[] elementData = this.elementData;
        int index = elementData.length - mFreeSpace;
        elementData[index]=block;
        block.setIndex(index);
        block.setParent(this);
        mFreeSpace --;
    }
    private int calculateAllocate(){
        mAllocateStep++;
        int amount = childesCount() / 4;
        if(amount < 10){
            amount = 10;
        }else if(amount > 100){
            amount = 100;
        }
        amount = amount * mAllocateStep;
        if(amount > 8000){
            amount = 8000;
        }
        return amount;
    }
    protected boolean isFlexible(){
        return false;
    }
    protected void trimAllocatedFreeSpace(){
        if(mFreeSpace <= 0){
            return;
        }
        int length = elementData.length - mFreeSpace;
        T[] update = newInstance(length);
        if (length > 0) {
            System.arraycopy(elementData, 0, update, 0, length);
        }
        elementData = update;
        mFreeSpace = 0;
    }
    public final int countNonNull(){
        return countNonNull(true);
    }
    public final int childesCount(){
        return elementData.length;
    }
    public T createNext(){
        T block=newInstance();
        add(block);
        return block;
    }
    public final T get(int i){
        if(i >= childesCount() || i<0){
            return null;
        }
        return elementData[i];
    }
    public final T getLast(){
        return get(childesCount() - mFreeSpace - 1);
    }
    public int indexOf(Object block){
        T[] items=elementData;
        if(items==null){
            return -1;
        }
        int len=items.length;
        for(int i=0;i iterator() {
        return iterator(false);
    }
    public Iterator iterator(boolean skipNullBlock) {
        trimAllocatedFreeSpace();
        return new BlockIterator(skipNullBlock);
    }
    public Iterator iterator(Predicate tester) {
        trimAllocatedFreeSpace();
        return new PredicateIterator(tester);
    }
    public boolean contains(Object block){
        T[] items = elementData;
        if(block == null || items==null){
            return false;
        }
        int length = items.length;
        for(int i = 0; i < length; i++){
            if(items[i] == block){
                return true;
            }
        }
        return false;
    }
    public void remove(Collection blockList){
        remove(blockList, null);
    }
    protected void remove(Collection blockList, Collection removedList){
        T[] items = elementData;
        if(items == null || blockList == null){
            return;
        }
        int length = items.length;
        if(length == 0){
            return;
        }
        Iterator iterator = blockList.iterator();
        while (iterator.hasNext()){
            T block = iterator.next();
            if(block == null){
                continue;
            }
            int index = block.getIndex();
            if(index < 0 || index >= length){
                continue;
            }
            T item = items[index];
            if(item != block){
                continue;
            }
            items[index] = null;
            onPreRemove(item);
            if(removedList != null){
                removedList.add(item);
            }
        }
        trimNullBlocks();
    }
    public void onPreRemove(T block){

    }
    public boolean remove(T block){
        return remove(block, true);
    }
    protected boolean remove(T block, boolean trim){
        T[] items = elementData;
        if(block == null){
            return false;
        }
        boolean found=false;
        int length = items.length;
        for(int i = 0; i < length; i++){
            T item = items[i];
            if(block == item){
                items[i] = null;
                found = true;
                onPreRemove(item);
            }
        }
        if(found && trim){
            trimNullBlocks();
        }
        return found;
    }
    protected void trimNullBlocks(){
        mFreeSpace = 0;
        T[] items=elementData;
        if(items==null){
            return;
        }
        int count=countNonNull(false);
        int len=items.length;
        if(count==len){
            return;
        }
        T[] update=newInstance(count);
        int index=0;
        for(int i=0;isize){
            end=size;
        }else {
            end=index;
        }
        if(end>0){
            System.arraycopy(old, 0, update, 0, end);
        }
        for(int i=end;i 0){
            return;
        }
        allocate(calculateAllocate());
    }
    private void allocate(int amount){
        if(amount <= 0 || mFreeSpace > 0){
            return;
        }
        mFreeSpace = amount;
        T[] old = elementData;
        int index = old.length;
        int size = index + amount;
        T[] update = newInstance(size);
        if(index == 0){
            elementData = update;
            return;
        }
        System.arraycopy(old, 0, update, 0, index);
        elementData = update;
    }

    @Override
    public String toString(){
        return "count="+ childesCount();
    }

    private static boolean isAllNull(Block[] itemsList){

        for(Block item : itemsList){
            if(item!=null && !item.isNull()){
                return false;
            }
        }
        return true;
    }

    private class BlockIterator implements Iterator {
        private int mCursor;
        private final int mMaxSize;
        private final boolean mSkipNullBlock;
        BlockIterator(boolean skipNullBlock){
            mSkipNullBlock=skipNullBlock;
            mCursor=0;
            mMaxSize=BlockArray.this.childesCount();
        }
        @Override
        public boolean hasNext() {
            checkCursor();
            return !isFinished();
        }
        @Override
        public T next() {
            if(!isFinished()){
                T item=BlockArray.this.get(mCursor);
                mCursor++;
                checkCursor();
                return item;
            }
            return null;
        }
        private boolean isFinished(){
            return mCursor>=mMaxSize;
        }
        private void checkCursor(){
            if(!mSkipNullBlock || isFinished()){
                return;
            }
            T item = BlockArray.this.get(mCursor);
            while (item == null || item.isNull()){
                mCursor++;
                item = BlockArray.this.get(mCursor);
                if(mCursor>=mMaxSize){
                    break;
                }
            }
        }
    }


    private class PredicateIterator implements Iterator {
        private int mCursor;
        private final int mMaxSize;
        private final Predicate mTester;
        PredicateIterator(Predicate tester){
            this.mTester = tester;
            mCursor = 0;
            mMaxSize = BlockArray.this.childesCount();
        }
        @Override
        public boolean hasNext() {
            checkCursor();
            return hasItems();
        }
        @Override
        public T next() {
            if(hasItems()){
                T item=BlockArray.this.get(mCursor);
                mCursor++;
                checkCursor();
                return item;
            }
            return null;
        }
        private boolean hasItems(){
            return mCursor < mMaxSize;
        }
        private void checkCursor(){
            if(mTester == null){
                return;
            }
            while (hasItems() && !test(BlockArray.this.get(getCursor()))){
                mCursor++;
            }
        }
        private int getCursor(){
            return mCursor;
        }
        private boolean test(T item){
            Predicate tester = mTester;
            if(tester != null){
                return tester.test(item);
            }
            return true;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy