001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.lang3.compare;
018
019import java.util.function.Predicate;
020
021/**
022 * <p>Utility library to provide helper methods for translating {@link Comparable#compareTo} result into a boolean.</p>
023 *
024 * <p>Example: {@code boolean x = is(myComparable).lessThanOrEqualTo(otherComparable)}</p>
025 *
026 * <p>#ThreadSafe#</p>
027 *
028 * @since 3.10
029 */
030public class ComparableUtils {
031
032    /**
033     * Provides access to the available methods
034     *
035     * @param <A> the type of objects that this object may be compared against.
036     */
037    public static class ComparableCheckBuilder<A extends Comparable<A>> {
038
039        private final A a;
040
041        private ComparableCheckBuilder(final A a) {
042            this.a = a;
043        }
044
045        /**
046         * Checks if {@code [b <= a <= c]} or {@code [b >= a >= c]} where the {@code a} is object passed to {@link #is}.
047         *
048         * @param b the object to compare to the base object
049         * @param c the object to compare to the base object
050         * @return true if the base object is between b and c
051         */
052        public boolean between(final A b, final A c) {
053            return betweenOrdered(b, c) || betweenOrdered(c, b);
054        }
055
056        /**
057         * Checks if {@code (b < a < c)} or {@code (b > a > c)} where the {@code a} is object passed to {@link #is}.
058         *
059         * @param b the object to compare to the base object
060         * @param c the object to compare to the base object
061         * @return true if the base object is between b and c and not equal to those
062         */
063        public boolean betweenExclusive(final A b, final A c) {
064            return betweenOrderedExclusive(b, c) || betweenOrderedExclusive(c, b);
065        }
066
067        private boolean betweenOrdered(final A b, final A c) {
068            return greaterThanOrEqualTo(b) && lessThanOrEqualTo(c);
069        }
070
071        private boolean betweenOrderedExclusive(final A b, final A c) {
072            return greaterThan(b) && lessThan(c);
073        }
074
075        /**
076         * Checks if the object passed to {@link #is} is equal to {@code b}
077         *
078         * @param b the object to compare to the base object
079         * @return true if the value returned by {@link Comparable#compareTo} is equal to {@code 0}
080         */
081        public boolean equalTo(final A b) {
082            return a.compareTo(b) == 0;
083        }
084
085        /**
086         * Checks if the object passed to {@link #is} is greater than {@code b}
087         *
088         * @param b the object to compare to the base object
089         * @return true if the value returned by {@link Comparable#compareTo} is greater than {@code 0}
090         */
091        public boolean greaterThan(final A b) {
092            return a.compareTo(b) > 0;
093        }
094
095        /**
096         * Checks if the object passed to {@link #is} is greater than or equal to {@code b}
097         *
098         * @param b the object to compare to the base object
099         * @return true if the value returned by {@link Comparable#compareTo} is greater than or equal to {@code 0}
100         */
101        public boolean greaterThanOrEqualTo(final A b) {
102            return a.compareTo(b) >= 0;
103        }
104
105        /**
106         * Checks if the object passed to {@link #is} is less than {@code b}
107         *
108         * @param b the object to compare to the base object
109         * @return true if the value returned by {@link Comparable#compareTo} is less than {@code 0}
110         */
111        public boolean lessThan(final A b) {
112            return a.compareTo(b) < 0;
113        }
114
115        /**
116         * Checks if the object passed to {@link #is} is less than or equal to {@code b}
117         *
118         * @param b the object to compare to the base object
119         * @return true if the value returned by {@link Comparable#compareTo} is less than or equal to {@code 0}
120         */
121        public boolean lessThanOrEqualTo(final A b) {
122            return a.compareTo(b) <= 0;
123        }
124    }
125
126    /**
127     * Checks if {@code [b <= a <= c]} or {@code [b >= a >= c]} where the {@code a} is the tested object.
128     *
129     * @param b the object to compare to the tested object
130     * @param c the object to compare to the tested object
131     * @param <A> type of the test object
132     * @return a predicate for true if the tested object is between b and c
133     */
134    public static <A extends Comparable<A>> Predicate<A> between(final A b, final A c) {
135        return a -> is(a).between(b, c);
136    }
137
138    /**
139     * Checks if {@code (b < a < c)} or {@code (b > a > c)} where the {@code a} is the tested object.
140     *
141     * @param b the object to compare to the tested object
142     * @param c the object to compare to the tested object
143     * @param <A> type of the test object
144     * @return a predicate for true if the tested object is between b and c and not equal to those
145     */
146    public static <A extends Comparable<A>> Predicate<A> betweenExclusive(final A b, final A c) {
147        return a -> is(a).betweenExclusive(b, c);
148    }
149
150    /**
151     * Checks if the tested object is greater than or equal to {@code b}
152     *
153     * @param b the object to compare to the tested object
154     * @param <A> type of the test object
155     * @return a predicate for true if the value returned by {@link Comparable#compareTo}
156     * is greater than or equal to {@code 0}
157     */
158    public static <A extends Comparable<A>> Predicate<A> ge(final A b) {
159        return a -> is(a).greaterThanOrEqualTo(b);
160    }
161
162    /**
163     * Checks if the tested object is greater than {@code b}
164     *
165     * @param b the object to compare to the tested object
166     * @param <A> type of the test object
167     * @return a predicate for true if the value returned by {@link Comparable#compareTo} is greater than {@code 0}
168     */
169    public static <A extends Comparable<A>> Predicate<A> gt(final A b) {
170        return a -> is(a).greaterThan(b);
171    }
172
173    /**
174     * Provides access to the available methods
175     *
176     * @param a base object in the further comparison
177     * @param <A> type of the base object
178     * @return a builder object with further methods
179     */
180    public static <A extends Comparable<A>> ComparableCheckBuilder<A> is(final A a) {
181        return new ComparableCheckBuilder<>(a);
182    }
183
184    /**
185     * Checks if the tested object is less than or equal to {@code b}
186     *
187     * @param b the object to compare to the tested object
188     * @param <A> type of the test object
189     * @return a predicate for true if the value returned by {@link Comparable#compareTo}
190     * is less than or equal to {@code 0}
191     */
192    public static <A extends Comparable<A>> Predicate<A> le(final A b) {
193        return a -> is(a).lessThanOrEqualTo(b);
194    }
195
196    /**
197     * Checks if the tested object is less than {@code b}
198     *
199     * @param b the object to compare to the tested object
200     * @param <A> type of the test object
201     * @return a predicate for true if the value returned by {@link Comparable#compareTo} is less than {@code 0}
202     */
203    public static <A extends Comparable<A>> Predicate<A> lt(final A b) {
204        return a -> is(a).lessThan(b);
205    }
206
207    private ComparableUtils() {}
208}