workcraft/workcraft

View on GitHub
workcraft/WorkcraftCore/src/org/workcraft/types/MultiSet.java

Summary

Maintainability
A
2 hrs
Test Coverage
package org.workcraft.types;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Set;

public class MultiSet<T> implements Set<T> {

    private final LinkedHashMap<T, Integer> map = new LinkedHashMap<>();

    @Override
    public int size() {
        int result = 0;
        for (T o: map.keySet()) {
            result += count(o);
        }
        return result;
    }

    @Override
    public boolean isEmpty() {
        return size() == 0;
    }

    @Override
    public boolean contains(Object o) {
        return count(o) > 0;
    }

    @Override
    public Iterator<T> iterator() {
        return new Iterator<T>() {
            private Iterator<T> cursor = map.keySet().iterator();
            private T current = null;
            private int currentIdx = 0;

            @Override
            public boolean hasNext() {
                boolean result = cursor.hasNext();
                if (!result && (current != null)) {
                    result = count(current) > currentIdx;
                }
                return result;
            }

            @Override
            public T next() {
                if (currentIdx  >= count(current)) {
                    current = cursor.next();
                    currentIdx = 0;
                }
                currentIdx++;
                return current;
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }

    @Override
    public Object[] toArray() {
        ArrayList<T> result = new ArrayList<>();
        for (T o: map.keySet()) {
            for (int i = 0; i < count(o); i++) {
                result.add(o);
            }
        }
        return result.toArray(new Object[result.size()]);
    }

    @SuppressWarnings("unchecked")
    @Override
    public <R> R[] toArray(R[] a) {
        int idx = 0;
        for (T o: map.keySet()) {
            for (int i = 0; i < count(o); i++) {
                if (idx > a.length) {
                    a[idx] = (R) o;
                }
            }
        }
        return a;
    }

    @Override
    public boolean add(T e) {
        return add(e, 1);
    }

    public boolean add(T e, int n) {
        boolean result = false;
        if (n > 0) {
            Integer count = 0;
            if (map.containsKey(e)) {
                count = map.get(e);
            }
            count += n;
            map.put(e, count);
            result = true;
        }
        return result;
    }

    @Override
    public boolean remove(Object o) {
        return remove(o, 1);
    }

    @SuppressWarnings("unchecked")
    public boolean remove(Object o, int n) {
        boolean result = false;
        Integer count = 0;
        if (map.containsKey(o)) {
            count = map.get(o);
        }
        if (count > n) {
            count -= n;
            map.put((T) o, count);
            result = true;
        } else {
            map.remove(o);
        }
        return result;
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        boolean result = true;
        for (Object o: c) {
            result &= map.containsKey(o);
        }
        return result;
    }

    @Override
    public boolean addAll(Collection<? extends T> c) {
        boolean result = false;
        if (c instanceof MultiSet<?>) {
            MultiSet<? extends T> otherMultiSet = (MultiSet<? extends T>) c;
            for (T o: otherMultiSet.map.keySet()) {
                result |= add(o, otherMultiSet.count(o));
            }
        } else {
            for (T o: c) {
                result |= add(o);
            }
        }
        return result;
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean retainAll(Collection<?> c) {
        boolean result = false;

        HashSet<Object> keys = new HashSet<>();
        keys.addAll(map.keySet());
        keys.addAll(c);

        MultiSet<Object> otherMultiset = null;
        if (c instanceof MultiSet<?>) {
            otherMultiset = (MultiSet<Object>) c;
        } else {
            otherMultiset = new MultiSet<>();
            otherMultiset.addAll(c);
        }

        for (Object o: keys) {
            int otherCount = otherMultiset.count(o);
            int thisCount = count(o);
            if (otherCount == 0) {
                map.remove(o);
                result = true;
            } else if (thisCount > otherCount) {
                map.put((T) o, otherCount);
                result = true;
            }
        }
        return result;
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        boolean result = false;
        if (c instanceof MultiSet<?>) {
            MultiSet<?> otherMultiSet = (MultiSet<?>) c;
            for (Object o: otherMultiSet.map.keySet()) {
                result |= remove(o, otherMultiSet.count(o));
            }
        } else {
            for (Object o: c) {
                result |= remove(o);
            }
        }
        return result;
    }

    @Override
    public void clear() {
        map.clear();
    }

    public int count(Object o) {
        int result = 0;
        if (map.containsKey(o)) {
            result = map.get(o);
        }
        return result;
    }

    public Set<T> toSet() {
        return map.keySet();
    }

}