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

com.speedment.runtime.field.internal.comparator.CombinedComparatorImpl Maven / Gradle / Ivy

Go to download

Partly generated model of the fields that represent columns in the database. Fields can be used to produce special predicates and functions that contain metadata that Speedment can analyze runtime.

There is a newer version: 3.2.10
Show newest version
/**
 *
 * Copyright (c) 2006-2017, Speedment, Inc. All Rights Reserved.
 *
 * 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.speedment.runtime.field.internal.comparator;

import com.speedment.runtime.field.ComparableField;
import com.speedment.runtime.field.Field;
import com.speedment.runtime.field.comparator.CombinedComparator;
import com.speedment.runtime.field.comparator.FieldComparator;
import com.speedment.runtime.field.comparator.NullOrder;
import com.speedment.runtime.field.method.*;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.Objects.requireNonNull;

/**
 * Default implementation of the {@link CombinedComparator}-interface.
 *
 * @author Emil Forslund
 * @since  3.0.11
 */
public final class CombinedComparatorImpl
implements CombinedComparator {

    private final List> comparators;

    public CombinedComparatorImpl(
            final List> comparators) {

        this.comparators = requireNonNull(comparators);
    }

    @Override
    public Stream> stream() {
        return comparators.stream();
    }

    @Override
    public int size() {
        return comparators.size();
    }

    @Override
    public int compare(ENTITY o1, ENTITY o2) {
        for (final FieldComparator comp : comparators) {
            final int c = comp.compare(o1, o2);
            if (c != 0) return c;
        }

        return 0;
    }

    @Override
    public CombinedComparator reversed() {
        return new CombinedComparatorImpl<>(comparators.stream()
            .map(FieldComparator::reversed)
            .collect(Collectors.toList())
        );
    }

    @Override
    public Comparator thenComparing(Comparator other) {
        return then(other);
    }

    @Override
    public  Comparator thenComparing(
            final Function keyExtractor,
            final Comparator keyComparator) {

        if (keyExtractor instanceof Getter) {
            @SuppressWarnings("unchecked")
            final Getter getter = (Getter) keyExtractor;
            final Optional> result = then(getter);
            if (result.isPresent()) {
                return result.get();
            }
        }

        return (a, b) -> {
            final int c = compare(a, b);
            if (c == 0) {
                return keyComparator.compare(
                    keyExtractor.apply(a),
                    keyExtractor.apply(b)
                );
            } else return c;
        };
    }

    @Override
    public > Comparator
    thenComparing(Function keyExtractor) {
        if (keyExtractor instanceof Getter) {
            @SuppressWarnings("unchecked")
            final Getter getter = (Getter) keyExtractor;
            final Optional> result = then(getter);
            if (result.isPresent()) {
                return result.get();
            }
        }

        return (a, b) -> {
            final int c = compare(a, b);
            if (c == 0) {
                final U oa = keyExtractor.apply(a);
                final U ob = keyExtractor.apply(b);
                if (oa == null && ob == null) {
                    return 0;
                } else if (oa == null) {
                    return 1;
                } else if (ob == null) {
                    return -1;
                } else {
                    return oa.compareTo(ob);
                }
            } else return c;
        };
    }

    @Override
    public Comparator
    thenComparingInt(ToIntFunction keyExtractor) {
        if (keyExtractor instanceof Getter) {
            @SuppressWarnings("unchecked")
            final Getter getter = (Getter) keyExtractor;
            final Optional> result = then(getter);
            if (result.isPresent()) {
                return result.get();
            }
        }

        return (a, b) -> {
            final int c = compare(a, b);
            if (c == 0) {
                final int oa = keyExtractor.applyAsInt(a);
                final int ob = keyExtractor.applyAsInt(b);
                return Integer.compare(oa, ob);
            } else return c;
        };
    }

    @Override
    public Comparator
    thenComparingLong(ToLongFunction keyExtractor) {
        if (keyExtractor instanceof Getter) {
            @SuppressWarnings("unchecked")
            final Getter getter = (Getter) keyExtractor;
            final Optional> result = then(getter);
            if (result.isPresent()) {
                return result.get();
            }
        }

        return (a, b) -> {
            final int c = compare(a, b);
            if (c == 0) {
                final long oa = keyExtractor.applyAsLong(a);
                final long ob = keyExtractor.applyAsLong(b);
                return Long.compare(oa, ob);
            } else return c;
        };
    }

    @Override
    public Comparator
    thenComparingDouble(ToDoubleFunction keyExtractor) {
        if (keyExtractor instanceof Getter) {
            @SuppressWarnings("unchecked")
            final Getter getter = (Getter) keyExtractor;
            final Optional> result = then(getter);
            if (result.isPresent()) {
                return result.get();
            }
        }

        return (a, b) -> {
            final int c = compare(a, b);
            if (c == 0) {
                final double oa = keyExtractor.applyAsDouble(a);
                final double ob = keyExtractor.applyAsDouble(b);
                return Double.compare(oa, ob);
            } else return c;
        };
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof CombinedComparator)) return false;

        final CombinedComparator that = (CombinedComparator) o;
        final Iterator> it =
            comparators.iterator();

        return that.stream().allMatch(
            c -> it.hasNext() && it.next().equals(c)
        ) && !it.hasNext();
    }

    @Override
    public int hashCode() {
        return 1299827 * comparators.hashCode();
    }

    @Override
    public String toString() {
        return "CombinedComparatorImpl" + comparators;
    }

    private Comparator then(Comparator other) {
        if (other instanceof FieldComparator) {
            @SuppressWarnings("unchecked")
            final FieldComparator fc =
                (FieldComparator) other;

            final List> copy =
                new ArrayList<>(comparators);

            copy.add(fc);

            return new CombinedComparatorImpl<>(copy);
        } else if (other instanceof CombinedComparator) {
            @SuppressWarnings("unchecked")
            final CombinedComparator cc =
                (CombinedComparator) other;

            final List> copy =
                new ArrayList<>(comparators);

            cc.stream().forEachOrdered(copy::add);

            return new CombinedComparatorImpl<>(copy);
        } else {
            return (a, b) -> {
                final int c = compare(a, b);
                return c == 0 ? other.compare(a, b) : c;
            };
        }
    }

    private >
    Optional> then(Getter getter) {

        if (getter instanceof GetByte) {
            @SuppressWarnings("unchecked")
            final GetByte casted = (GetByte) getter;
            return Optional.of(then(new ByteFieldComparatorImpl<>(
                casted.getField())
            ));
        } else if (getter instanceof GetShort) {
            @SuppressWarnings("unchecked")
            final GetShort casted = (GetShort) getter;
            return Optional.of(then(new ShortFieldComparatorImpl<>(
                casted.getField())
            ));
        } else if (getter instanceof GetInt) {
            @SuppressWarnings("unchecked")
            final GetInt casted = (GetInt) getter;
            return Optional.of(then(new IntFieldComparatorImpl<>(
                casted.getField())
            ));
        } else if (getter instanceof GetLong) {
            @SuppressWarnings("unchecked")
            final GetLong casted = (GetLong) getter;
            return Optional.of(then(new LongFieldComparatorImpl<>(
                casted.getField())
            ));
        } else if (getter instanceof GetFloat) {
            @SuppressWarnings("unchecked")
            final GetFloat casted = (GetFloat) getter;
            return Optional.of(then(new FloatFieldComparatorImpl<>(
                casted.getField())
            ));
        } else if (getter instanceof GetDouble) {
            @SuppressWarnings("unchecked")
            final GetDouble casted = (GetDouble) getter;
            return Optional.of(then(new DoubleFieldComparatorImpl<>(
                casted.getField())
            ));
        } else if (getter instanceof GetChar) {
            @SuppressWarnings("unchecked")
            final GetChar casted = (GetChar) getter;
            return Optional.of(then(new CharFieldComparatorImpl<>(
                casted.getField())
            ));
        } else if (getter instanceof GetReference) {
            @SuppressWarnings("unchecked")
            final GetReference casted = (GetReference) getter;
            final Field field = casted.getField();
            if (field instanceof ComparableField) {
                return Optional.of(then(new ReferenceFieldComparatorImpl<>(
                    (ComparableField) casted.getField(),
                    NullOrder.LAST
                )));
            }
        }

        return Optional.empty();
    }
}