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

com.moon.core.util.TableImpl Maven / Gradle / Ivy

package com.moon.core.util;

import com.moon.core.util.function.TableConsumer;

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

import static java.util.Collections.EMPTY_SET;

/**
 * @author moonsky
 */
public class TableImpl implements Table {

    protected transient Map> table;

    protected transient Supplier>> containerCreator;

    protected transient Function> rowCreator;

    public TableImpl() { this(x -> new HashMap<>()); }

    public TableImpl(Function> rowCreator) { this(HashMap::new, rowCreator); }

    public TableImpl(Supplier>> containerCreator, Function> rowCreator) {
        this.containerCreator = containerCreator;
        this.rowCreator = rowCreator;
    }

    public static  TableImpl newHashTable() { return new TableImpl<>(); }

    public static  TableImpl newLinkedHashTable() {
        return new TableImpl<>(() -> new LinkedHashMap<>(), x -> new LinkedHashMap<>());
    }

    public static  TableImpl newWeakHashTable() {
        return new TableImpl<>(() -> new WeakHashMap<>(), x -> new WeakHashMap<>());
    }

    private Map ensureTable() {
        Map> table = this.table;
        if (table == null) {
            table = containerCreator.get();
            this.table = table;
        }
        return table;
    }

    private Map ensureRow(Object x) {
        Map> table = this.ensureTable();
        Map row = table.get(x);
        if (row == null) {
            row = rowCreator.apply(x);
            table.put((X) x, row);
        }
        return row;
    }

    private Map nullableRow(Object x) {
        Map> table = this.table;
        return table == null ? null : table.get(x);
    }

    @Override
    public Z put(X x, Y y, Z z) { return ensureRow(x).put(y, z); }

    @Override
    public Z putIfAbsent(X x, Y y, Z z) { return ensureRow(x).putIfAbsent(y, z); }

    @Override
    public Z get(Object x, Object y) {
        Map row = nullableRow(x);
        return row == null ? null : row.get(y);
    }

    @Override
    public Map put(X x, Map map) {
        Map> table = this.ensureTable();
        return table.put(x, (Map) map);
    }

    @Override
    public void putAll(X x, Map map) {
        Map row = ensureRow(x);
        row.putAll(map);
    }

    @Override
    public Map get(Object x) { return nullableRow(x); }

    @Override
    public void putAll(Table table) {
        if (table != null) {
            X x;
            Map row, inputRow;
            Map> present = this.ensureTable();
            for (Map.Entry> entry : table.rowsEntrySet()) {
                inputRow = entry.getValue();
                x = entry.getKey();
                row = present.get(x);
                if (row == null) {
                    if (inputRow == null) {
                        present.put(x, null);
                    } else {
                        row = rowCreator.apply(x);
                        row.putAll(inputRow);
                        present.put(x, row);
                    }
                } else {
                    if (inputRow != null) {
                        row.putAll(inputRow);
                    }
                }
            }
        }
    }

    @Override
    public Z remove(Object x, Object y) {
        Map row = nullableRow(x);
        if (row == null) {
            return null;
        } else {
            return row.remove(y);
        }
    }

    @Override
    public Map remove(Object x) { return table == null ? null : table.remove(x); }

    @Override
    public boolean containsValue(Object value) {
        Map> table = this.table;
        if (table == null) {
            return false;
        } else {
            for (Map.Entry> xMapEntry : table.entrySet()) {
                Map row = xMapEntry.getValue();
                if (row.containsValue(value)) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public Set keys() { return table == null ? EMPTY_SET : table.keySet(); }

    @Override
    public Collection> rows() { return table == null ? EMPTY_SET : table.values(); }

    @Override
    public Set>> rowsEntrySet() { return table == null ? EMPTY_SET : table.entrySet(); }

    @Override
    public void forEach(TableConsumer consumer) {
        Set>> entries = rowsEntrySet();
        for (Map.Entry> entry : entries) {
            Map row = entry.getValue();
            X x = entry.getKey();
            if (row != null) {
                row.forEach((key, value) -> consumer.accept(x, key, value));
            }
        }
    }

    @Override
    public void clear() { this.table = null; }

    @Override
    public int sizeOfRows() { return table == null ? 0 : table.size(); }

    @Override
    public int maxSizeOfColumns() { return obtainSize(0, Math::max); }

    @Override
    public int minSizeOfColumns() { return obtainSize(Integer.MAX_VALUE, Math::min); }

    @Override
    public int size() { return obtainSize(0, TableImpl::sum); }

    public TableImpl sandbox(
        Function> rowCreator,
        Consumer> consumer
    ) {
        Function supplier = this.rowCreator;
        this.rowCreator = rowCreator;
        consumer.accept(this);
        this.rowCreator = supplier;
        return this;
    }

    private int obtainSize(int initialize, IntCalculator calculator) {
        Map> table = this.table;
        if (table == null || table.isEmpty()) {
            return 0;
        } else {
            int size = initialize;
            for (Map.Entry> xMapEntry : table.entrySet()) {
                Map row = xMapEntry.getValue();
                if (row != null && !row.isEmpty()) {
                    size = calculator.calc(size, row.size());
                }
            }
            return size;
        }
    }

    private static int sum(int v1, int v2) { return v1 + v2; }

    interface IntCalculator {

        int calc(int prev, int size);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy