net.darkmist.clf.Util.java Source code

Java tutorial

Introduction

Here is the source code for net.darkmist.clf.Util.java

Source

/*
 *  Copyright (C) 2012 Ed Schaller <schallee@darkmist.net>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package net.darkmist.clf;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class Util {
    private static final Class<Util> CLASS = Util.class;
    private static final Log logger = LogFactory.getLog(CLASS);

    public interface Converter<T, U> {
        public U convert(T src);
    }

    private static Converter<String, File> stringToFileConverter = new Converter<String, File>() {
        public File convert(String name) {
            return new File(name);
        }
    };

    public static Converter<String, File> getStringToFileConverter() {
        return stringToFileConverter;
    }

    public static <T extends Closeable> T close(T toClose, Log logExceptionTo, String name) {
        if (toClose == null)
            return null;
        try {
            toClose.close();
        } catch (IOException e) {
            logExceptionTo.warn("IOException closing " + name + " ignored.", e);
        }
        return null;
    }

    public static <T extends Closeable> T close(T toClose, String name) {
        return close(toClose, logger, name);
    }

    public static <T extends Closeable> T close(T toClose) {
        if (toClose == null)
            return null;
        return close(toClose, logger, toClose.toString());
    }

    public static <T> Queue<T> newQueue() {
        return new LinkedList<T>();
    }

    public static <T> Queue<T> addTo(Queue<T> q, T[] toAdd, int off, int len) {
        int end = Math.min(len + off, toAdd.length);

        for (int c = off; c < end; c++)
            q.offer(toAdd[c]);
        return q;
    }

    public static <T> Queue<T> addTo(Queue<T> q, T... contents) {
        return addTo(q, contents, 0, contents.length);
    }

    public static <T> Queue<T> newQueue(T[] contents, int off, int len) {
        Queue<T> q = newQueue();

        return addTo(q, contents, off, len);
    }

    public static <T> Queue<T> newQueue(T... contents) {
        return newQueue(contents, 0, contents.length);
    }

    public static <U, T> Queue<T> addTo(Queue<T> q, Converter<U, T> converter, U[] toAdd, int off, int len) {
        int end = Math.min(len + off, toAdd.length);

        for (int c = off; c < end; c++)
            q.offer(converter.convert(toAdd[c]));
        return q;
    }

    public static <U, T> Queue<T> addTo(Queue<T> q, Converter<U, T> converter, U... toAdd) {
        return addTo(q, converter, toAdd, 0, toAdd.length);
    }

    public static <U, T> Queue<T> newQueue(Converter<U, T> converter, U[] contents, int off, int len) {
        Queue<T> q = newQueue();
        return addTo(q, converter, contents, off, len);
    }

    public static <U, T> Queue<T> newQueue(Converter<U, T> converter, U... contents) {
        return newQueue(converter, contents, 0, contents.length);
    }

    public static <T> T[] concat(T[] a, T[] b, T[] dest) {
        System.arraycopy(a, 0, dest, 0, a.length);
        System.arraycopy(b, 0, dest, a.length, b.length);
        return dest;
    }

    private static class ComparableComparator<T extends Comparable<T>> implements Comparator<T>, Serializable {
        private static final long serialVersionUID = 1l;
        @SuppressWarnings("unchecked")
        private static ComparableComparator singleton = new ComparableComparator();

        @SuppressWarnings("unchecked")
        static <U extends Comparable<U>> Comparator<U> instance() {
            return singleton;
        }

        private ComparableComparator() {
        }

        public int compare(T a, T b) {
            return a.compareTo(b);
        }
    }

    public static <T extends Comparable<T>> Comparator<T> getComparableComparator() {
        return ComparableComparator.instance();
    }

    public static <T> T[] merge(T[] a, T[] b, T[] dest, Comparator<T> comparator) {
        int ai, bi, di;
        int dlen = a.length + b.length;

        if (dest.length < dlen)
            throw new IllegalArgumentException("Destination array is not large enough");

        // check for simple case where one whole array goes before the other
        if (comparator.compare(a[a.length - 1], b[0]) <= 0)
            return concat(a, b, dest);
        if (comparator.compare(b[b.length - 1], a[0]) <= 0)
            return concat(b, a, dest);

        // binarySearch for the start of one in the other
        if (comparator.compare(a[0], b[0]) <= 0) { // a starts, figure out where b[0] is 
            ai = Arrays.binarySearch(a, b[0], comparator);
            if (ai < 0) // ai = (-(insersion_point)-1)
                ai = -(ai + 1);
            System.arraycopy(a, 0, dest, 0, ai);
            di = ai;
            bi = 0;
        } else { // b starts, figure out where a[0] is
            bi = Arrays.binarySearch(b, a[0], comparator);
            if (bi < 0) // bi = (-(insersion_point)-1)
                bi = -(bi + 1);
            System.arraycopy(b, 0, dest, 0, bi);
            di = bi;
            ai = 0;
        }
        if (logger.isDebugEnabled())
            logger.debug("ai=" + ai + " bi=" + bi + " di=" + di);

        // merge until we run out of one
        for (; ai < a.length && bi < b.length; di++) {
            if (comparator.compare(a[ai], b[bi]) <= 0)
                dest[di] = a[ai++];
            else
                dest[di] = b[bi++];
        }

        // one array has been used up here...copy the rest
        if (ai < a.length)
            System.arraycopy(a, ai, dest, di, a.length - ai);
        else
            System.arraycopy(b, bi, dest, di, b.length - bi);

        return dest;
    }

    public static <U, T extends Collection<U>> T checkedAdd(T collection, U element) {
        if (!collection.add(element))
            throw new IllegalStateException("Collection " + collection + " refused to add element " + element);
        return collection;
    }

    public static <U, T extends Collection<U>> T append(T dest, Iterator<U> i) {
        while (i.hasNext())
            checkedAdd(dest, i.next());
        return dest;
    }

    public static <T, U extends Collection<T>> U merge(Iterator<T> ai, Iterator<T> bi, U dest,
            Comparator<T> comparator) {
        T af, bf; // first elements

        // get the initial stat of the iterators
        if (!ai.hasNext())
            return append(dest, bi);
        if (!bi.hasNext())
            return append(dest, ai);
        af = ai.next();
        bf = bi.next();

        while (true) {
            if (comparator.compare(af, bf) <= 0) {
                checkedAdd(dest, af);
                if (!ai.hasNext()) { // nothing left in a
                    checkedAdd(dest, bf);
                    return append(dest, bi);
                }
                af = ai.next();
            } else {
                checkedAdd(dest, bf);
                if (!bi.hasNext()) { // nothing left in b
                    checkedAdd(dest, af);
                    return append(dest, ai);
                }
                bf = bi.next();
            }
        }
    }
}