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 *      https://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
021import org.apache.commons.lang3.ObjectUtils;
022
023/**
024 * Helper translating {@link Comparable#compareTo} results to booleans.
025 *
026 * <p>
027 * Example: {@code boolean x = ComparableUtils.is(myComparable).lessThanOrEqualTo(otherComparable)}
028 * </p>
029 *
030 * <p>
031 * #ThreadSafe#
032 * </p>
033 *
034 * @since 3.10
035 */
036public class ComparableUtils {
037
038    /**
039     * Compares objects of a given generic type {@code A}.
040     *
041     * @param <A> The type of objects that this object may be compared against.
042     */
043    public static class ComparableCheckBuilder<A extends Comparable<A>> {
044
045        private final A a;
046
047        private ComparableCheckBuilder(final A a) {
048            this.a = a;
049        }
050
051        /**
052         * Tests if {@code [b <= a <= c]} or {@code [b >= a >= c]} where the {@code a} is object passed to {@link #is}.
053         *
054         * @param b The object to compare to the base object
055         * @param c The object to compare to the base object
056         * @return true if the base object is between b and c
057         */
058        public boolean between(final A b, final A c) {
059            return betweenOrdered(b, c) || betweenOrdered(c, b);
060        }
061
062        /**
063         * Tests if {@code (b < a < c)} or {@code (b > a > c)} where the {@code a} is object passed to {@link #is}.
064         *
065         * @param b The object to compare to the base object
066         * @param c The object to compare to the base object
067         * @return true if the base object is between b and c and not equal to those
068         */
069        public boolean betweenExclusive(final A b, final A c) {
070            return betweenOrderedExclusive(b, c) || betweenOrderedExclusive(c, b);
071        }
072
073        private boolean betweenOrdered(final A b, final A c) {
074            return greaterThanOrEqualTo(b) && lessThanOrEqualTo(c);
075        }
076
077        private boolean betweenOrderedExclusive(final A b, final A c) {
078            return greaterThan(b) && lessThan(c);
079        }
080
081        /**
082         * Tests if the object passed to {@link #is} is equal to {@code b}
083         *
084         * @param b The object to compare to the base object
085         * @return true if the value returned by {@link Comparable#compareTo} is equal to {@code 0}
086         */
087        public boolean equalTo(final A b) {
088            return a != null && a.compareTo(b) == 0;
089        }
090
091        /**
092         * Tests if the object passed to {@link #is} is greater than {@code b}
093         *
094         * @param b The object to compare to the base object
095         * @return true if the value returned by {@link Comparable#compareTo} is greater than {@code 0}
096         */
097        public boolean greaterThan(final A b) {
098            return a != null && a.compareTo(b) > 0;
099        }
100
101        /**
102         * Tests if the object passed to {@link #is} is greater than or equal to {@code b}
103         *
104         * @param b The object to compare to the base object
105         * @return true if the value returned by {@link Comparable#compareTo} is greater than or equal to {@code 0}
106         */
107        public boolean greaterThanOrEqualTo(final A b) {
108            return a != null && a.compareTo(b) >= 0;
109        }
110
111        /**
112         * Tests if the object passed to {@link #is} is less than {@code b}
113         *
114         * @param b The object to compare to the base object
115         * @return true if the value returned by {@link Comparable#compareTo} is less than {@code 0}
116         */
117        public boolean lessThan(final A b) {
118            return a != null && a.compareTo(b) < 0;
119        }
120
121        /**
122         * Tests if the object passed to {@link #is} is less than or equal to {@code b}
123         *
124         * @param b The object to compare to the base object
125         * @return true if the value returned by {@link Comparable#compareTo} is less than or equal to {@code 0}
126         */
127        public boolean lessThanOrEqualTo(final A b) {
128            return a != null && a.compareTo(b) <= 0;
129        }
130    }
131
132    /**
133     * Creates a predicate to test if {@code [b <= a <= c]} or {@code [b >= a >= c]} where the {@code a} is the tested object.
134     *
135     * @param b The object to compare to the tested object
136     * @param c The object to compare to the tested object
137     * @param <A> type of the test object
138     * @return A predicate for true if the tested object is between b and c
139     */
140    public static <A extends Comparable<A>> Predicate<A> between(final A b, final A c) {
141        return a -> is(a).between(b, c);
142    }
143
144    /**
145     * Creates a predicate to test if {@code (b < a < c)} or {@code (b > a > c)} where the {@code a} is the tested object.
146     *
147     * @param b The object to compare to the tested object
148     * @param c The object to compare to the tested object
149     * @param <A> type of the test object
150     * @return A predicate for true if the tested object is between b and c and not equal to those
151     */
152    public static <A extends Comparable<A>> Predicate<A> betweenExclusive(final A b, final A c) {
153        return a -> is(a).betweenExclusive(b, c);
154    }
155
156    /**
157     * Creates a predicate to test if the tested object is greater than or equal to {@code b}
158     *
159     * @param b The object to compare to the tested object
160     * @param <A> type of the test object
161     * @return A predicate for true if the value returned by {@link Comparable#compareTo}
162     * is greater than or equal to {@code 0}
163     */
164    public static <A extends Comparable<A>> Predicate<A> ge(final A b) {
165        return a -> is(a).greaterThanOrEqualTo(b);
166    }
167
168    /**
169     * Creates a predicate to test if the tested object is greater than {@code b}
170     *
171     * @param b The object to compare to the tested object
172     * @param <A> type of the test object
173     * @return A predicate for true if the value returned by {@link Comparable#compareTo} is greater than {@code 0}
174     */
175    public static <A extends Comparable<A>> Predicate<A> gt(final A b) {
176        return a -> is(a).greaterThan(b);
177    }
178
179    /**
180     * Creates a new {@link ComparableCheckBuilder}.
181     *
182     * @param a base object in the further comparison
183     * @param <A> type of the base object
184     * @return A builder object with further methods
185     */
186    public static <A extends Comparable<A>> ComparableCheckBuilder<A> is(final A a) {
187        return new ComparableCheckBuilder<>(a);
188    }
189
190    /**
191     * Creates a predicate to test if the tested object is less than or equal to {@code b}
192     *
193     * @param b The object to compare to the tested object
194     * @param <A> type of the test object
195     * @return A predicate for true if the value returned by {@link Comparable#compareTo}
196     * is less than or equal to {@code 0}
197     */
198    public static <A extends Comparable<A>> Predicate<A> le(final A b) {
199        return a -> is(a).lessThanOrEqualTo(b);
200    }
201
202    /**
203     * Creates a predicate to test if the tested object is less than {@code b}
204     *
205     * @param b The object to compare to the tested object
206     * @param <A> type of the test object
207     * @return A predicate for true if the value returned by {@link Comparable#compareTo} is less than {@code 0}
208     */
209    public static <A extends Comparable<A>> Predicate<A> lt(final A b) {
210        return a -> is(a).lessThan(b);
211    }
212
213    /**
214     * Returns the greater of two {@link Comparable} values, ignoring null.
215     * <p>
216     * For three or more values, use {@link ObjectUtils#max(Comparable...)}.
217     * </p>
218     *
219     * @param <A> Type of what we are comparing.
220     * @param comparable1 The first comparable, may be null.
221     * @param comparable2 The second comparable, may be null.
222     * @return The largest of {@code comparable1} and {@code comparable2}.
223     * @see ObjectUtils#max(Comparable...)
224     * @since 3.13.0
225     */
226    public static <A extends Comparable<A>> A max(final A comparable1, final A comparable2) {
227        return ObjectUtils.compare(comparable1, comparable2, false) > 0 ? comparable1 : comparable2;
228    }
229
230    /**
231     * Returns the lesser of two {@link Comparable} values, ignoring null.
232     * <p>
233     * For three or more values, use {@link ObjectUtils#min(Comparable...)}.
234     * </p>
235     *
236     * @param <A> Type of what we are comparing.
237     * @param comparable1 The first comparable, may be null.
238     * @param comparable2 The second comparable, may be null.
239     * @return The smallest of {@code comparable1} and {@code comparable2}.
240     * @see ObjectUtils#min(Comparable...)
241     * @since 3.13.0
242     */
243    public static <A extends Comparable<A>> A min(final A comparable1, final A comparable2) {
244        return ObjectUtils.compare(comparable1, comparable2, true) < 0 ? comparable1 : comparable2;
245    }
246
247    private ComparableUtils() {
248        // empty
249    }
250}