001/*
002 * ============================================================================
003 * Copyright © 2002-2024 by Thomas Thrien.
004 * All Rights Reserved.
005 * ============================================================================
006 * Licensed to the public under the agreements of the GNU Lesser General Public
007 * License, version 3.0 (the "License"). You may obtain a copy of the License at
008 *
009 *      http://www.gnu.org/licenses/lgpl.html
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, WITHOUT
013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
014 * License for the specific language governing permissions and limitations
015 * under the License.
016 */
017
018package org.tquadrat.foundation.util;
019
020import static java.lang.Integer.signum;
021import static java.lang.String.CASE_INSENSITIVE_ORDER;
022import static java.util.Comparator.naturalOrder;
023import static org.apiguardian.api.API.Status.STABLE;
024import static org.tquadrat.foundation.lang.Objects.requireNonNullArgument;
025
026import java.util.Comparator;
027
028import org.apiguardian.api.API;
029import org.tquadrat.foundation.annotation.ClassVersion;
030import org.tquadrat.foundation.annotation.UtilityClass;
031import org.tquadrat.foundation.exception.PrivateConstructorForStaticClassCalledError;
032import org.tquadrat.foundation.lang.StringConverter;
033import org.tquadrat.foundation.util.internal.KeyBasedComparator;
034import org.tquadrat.foundation.util.internal.ListBasedComparator;
035import org.tquadrat.foundation.util.internal.StringBasedComparator;
036
037/**
038 *  This class provides factory methods for a bunch of different
039 *  implementations of
040 *  {@link Comparator}.
041 *
042 *  @extauthor Thomas Thrien - thomas.thrien@tquadrat.org
043 *  @version $Id: Comparators.java 1084 2024-01-03 15:31:20Z tquadrat $
044 *  @since 0.0.5
045 *
046 *  @UMLGraph.link
047 */
048@UtilityClass
049@ClassVersion( sourceVersion = "$Id: Comparators.java 1084 2024-01-03 15:31:20Z tquadrat $" )
050@API( status = STABLE, since = "0.0.5" )
051public final class Comparators
052{
053        /*---------------*\
054    ====** Inner Classes **====================================================
055        \*---------------*/
056    /**
057     *  <p>{@summary Implementations of this interface provides the sort order
058     *  key from the given instance of the type.}</p>
059     *  <p>Usually the implementation of
060     *  {@link #getKey(Object) getKey()}
061     *  must ensure that the returned keys are distinct for distinct arguments.
062     *  This means for the arguments {@code a1} and {@code a2}, and the
063     *  generated keys <code>k<sub>a1</sub></code> and
064     *  <code>k<sub>a2</sub></code> that the following must be both
065     *  {@code true}:</p>
066     *  <ul>
067     *      <li><code>a1&nbsp;=&nbsp;a2&nbsp;&#x21d4;&nbsp;k<sub>a1</sub>&nbsp;=&nbsp;k<sub>a2</sub></code></li>
068     *      <li><code>a1&nbsp;&#x2260;&nbsp;a2&nbsp;&#x21d4;&nbsp;k<sub>a1</sub>&nbsp;&#x2260;&nbsp;k<sub>a2</sub></code></li>
069     *  </ul>
070     *  <p>This also requires that {@code getKey()} for the same argument must
071     *  provide always the same key.</p>
072     *
073     *  @extauthor Thomas Thrien - thomas.thrien@tquadrat.org
074     *  @version $Id: Comparators.java 1084 2024-01-03 15:31:20Z tquadrat $
075     *  @since 0.0.5
076     *
077     *  @param  <T> The type to order.
078     *  @param  <K> The key type that is used to determine the order; this may
079     *      be the same as the type itself.
080     *
081     *  @UMLGraph.link
082     */
083    @API( status = STABLE, since = "0.0.5" )
084    @ClassVersion( sourceVersion = "$Id: Comparators.java 1084 2024-01-03 15:31:20Z tquadrat $" )
085    @FunctionalInterface
086    public interface KeyProvider<T,K>
087    {
088            /*---------*\
089        ====** Methods **======================================================
090            \*---------*/
091        /**
092         *  Returns the sort order key for the given instance.
093         *
094         *  @param  instance    The instance; may be {@code null}.
095         *  @return The respective sort order key; will be {@code null} if
096         *      the {@code instance} was {@code null}.
097         */
098        public K getKey( T instance );
099    }
100    //  interface KeyProvider
101
102        /*--------------*\
103    ====** Constructors **=====================================================
104        \*--------------*/
105    /**
106     *  No instance allowed for this class.
107     */
108    private Comparators() { throw new PrivateConstructorForStaticClassCalledError( Comparators.class ); }
109
110        /*---------*\
111    ====** Methods **==========================================================
112        \*---------*/
113    /**
114     *  Returns a comparator that compares Strings ignoring the case.<br>
115     *  <br>Internally this is
116     *  {@link String#CASE_INSENSITIVE_ORDER},
117     *  with the limitations described there.
118     *
119     *  @return The comparator.
120     */
121    @API( status = STABLE, since = "0.0.5" )
122    public static final Comparator<String> caseInsensitiveComparator() { return CASE_INSENSITIVE_ORDER; }
123
124    /**
125     *  Returns a comparator that generates a sort key from the elements before
126     *  sorting them.<br>
127     *  <br>The implementation of this comparator generates the sort keys for
128     *  each and every comparison. This is obviously not very efficient. A more
129     *  efficient implementation is provided by
130     *  {@link #keyBasedComparator(KeyProvider, Comparator, boolean)}
131     *
132     *  @param  <T> The type to compare.
133     *  @param  <K> The key type that is used to determine the order; this may
134     *      be the same as the type itself.
135     *  @param  keyProvider The method that generates the sort key.
136     *  @return The comparator.
137     *
138     *  @note The key provider must return {@code null} for a {@code null}
139     *      value, as described for
140     *      {@link KeyProvider#getKey(Object)}.
141     *
142     *  @see KeyProvider
143     */
144    @API( status = STABLE, since = "0.0.5" )
145    public static final <T, K extends Comparable<K>> Comparator<T> keyBasedComparator( final KeyProvider<? super T, K> keyProvider )
146    {
147        requireNonNullArgument( keyProvider, "keyProvider" );
148        final var retValue = (Comparator<T>) ( o1, o2) -> signum( keyProvider.getKey( o1 ).compareTo( keyProvider.getKey( o2 ) ) );
149
150        //---* Done *----------------------------------------------------------
151        return retValue;
152    }   //  keyBasedComparator()
153
154    /**
155     *  A comparator that generates a sort key from the elements before sorting
156     *  them.<br>
157     *  <br>As it is not very efficient to generate the sort keys for each and
158     *  every comparison, it is possible to cache them.
159     *
160     *  @param  <T> The type to compare.
161     *  @param  <K> The key type that is used to determine the order; this may
162     *      be the same as the type itself.
163     *  @param  keyProvider The method that generates the sort key.
164     *  @param  keyComparator   The comparator that determines the order for
165     *      the keys.
166     *  @param  cacheKeys   A flag that determines whether the keys are to be
167     *      cached internally; {@code true} means they are kept, {@code false}
168     *      means that the keys are generated newly for each comparison.
169     *  @return The comparator.
170     *
171     *  @note The key provider must return {@code null} for a {@code null}
172     *      value, as described for
173     *      {@link KeyProvider#getKey(Object)}.
174     *  @note The internally used cache will be kept for later uses of the
175     *      comparator; this means that the key provider may not change its
176     *      behaviour meanwhile.
177     *  @note The internal cache is based on an
178     *      {@link java.util.IdentityHashMap IdentityHashMap}
179     *      with instances of the argument type <code>&lt;T&gt;</code> as the
180     *      key. If the key generation through the key provider will provide
181     *      equal keys for non-identical, but otherwise equal arguments, the
182     *      cache may not be efficient.
183     *
184     *  @see KeyProvider
185     */
186    @API( status = STABLE, since = "0.0.5" )
187    public static final <T, K> Comparator<T> keyBasedComparator( final KeyProvider<T,K> keyProvider, final Comparator<K> keyComparator, final boolean cacheKeys )
188    {
189        return new KeyBasedComparator<>( keyProvider, keyComparator, cacheKeys );
190    }   //  keyBasedComparator()
191
192    /**
193     *  <p>{@summary Returns a comparator that works on a list of sort
194     *  keys.}</p>
195     *  <p>Sometimes, a special sort order is required that cannot be defined
196     *  as a rule based on the values themselves. Instead an ordered list of
197     *  values defines their sequence.</p>
198     *  <p>This method creates a new
199     *  {@link Comparator}
200     *  instance that works on the given list of values. Values that are not on
201     *  that list will be placed to the end, ordered according to their natural
202     *  order.</p>
203     *
204     *  @param  <T> The type to compare.
205     *  @param  values  The values in their order.
206     *  @return The comparator.
207     */
208    @SafeVarargs
209    @API( status = STABLE, since = "0.0.5" )
210    public static final <T extends Comparable<T>> Comparator<T> listBasedComparator( final T... values )
211    {
212        final var retValue = new ListBasedComparator<T,T>( t -> t, naturalOrder(), requireNonNullArgument( values, "values" ).clone() );
213
214        //---* Done *----------------------------------------------------------
215        return retValue;
216    }   //  listBasedComparator()
217
218    /**
219     *  <p>{@summary A comparator that works on a list of sort keys.}</p>
220     *  <p>Sometimes, a special sort order is required that cannot be defined
221     *  as a rule based on the values themselves. Instead an ordered list of
222     *  keys defines their sequence.</p>
223     *  <p>The implementation first determines the key for a given value, then
224     *  it looks up that key in the key list to determine the sort order.
225     *  Values whose keys are not in the key list are ordered based on the
226     *  natural sort order of the keys.
227     *
228     *  @param  <T> The type to compare.
229     *  @param  <K> The key type that is used to determine the order; this may
230     *      be the same as the type itself.
231     *  @param  keyProvider The implementation of
232     *      {@link Comparators.KeyProvider}
233     *      that returns the sort keys for the instances to compare.
234     *  @param  keys    The sort order keys.
235     *  @return The comparator.
236     */
237    @API( status = STABLE, since = "0.0.5" )
238    @SafeVarargs
239    public static final <T,K extends Comparable<K>> Comparator<T> listBasedComparator( final KeyProvider<T,K> keyProvider, final K... keys )
240    {
241        final var retValue = new ListBasedComparator<>( keyProvider, naturalOrder(), requireNonNullArgument( keys, "keys" ).clone() );
242
243        //---* Done *----------------------------------------------------------
244        return retValue;
245    }   //  listBasedComparator()
246
247    /**
248     *  <p>{@summary A comparator that works on a list of sort keys.}</p>
249     *  <p>Sometimes, a special sort order is required that cannot be defined
250     *  as a rule based on the values themselves. Instead an ordered list of
251     *  keys defines their sequence.</p>
252     *  <p>The implementation first determines the key for a given value, then
253     *  it looks up that key in the key list to determine the sort order.
254     *  Values whose keys are not in the key list are ordered based on the
255     *  order of their keys that is implied by the given comparator.
256     *
257     *  @param  <T> The type to compare.
258     *  @param  <K> The key type that is used to determine the order; this may
259     *      be the same as the type itself.
260     *  @param  keyProvider The implementation of
261     *      {@link org.tquadrat.foundation.util.Comparators.KeyProvider}
262     *      that returns the sort keys for the instances to compare.
263     *  @param  comparator  The comparator that is used to order the instances
264     *      that are not listed.
265     *  @param  keys    The sort order keys.
266     *  @return The comparator.
267     */
268    @SafeVarargs
269    @API( status = STABLE, since = "0.0.5" )
270    public static final <T,K> Comparator<T> listBasedComparator( final KeyProvider<T,K> keyProvider, final Comparator<? super K> comparator, final K... keys )
271    {
272        final var retValue = new ListBasedComparator<>( keyProvider, comparator, requireNonNullArgument( keys, "keys" ).clone() );
273
274        //---* Done *----------------------------------------------------------
275        return retValue;
276    }   //  ListBasedComparator()
277
278    /**
279     *  A comparator for numeric values.
280     *
281     *  @param  <T> The type to compare.
282     *  @return The comparator.
283     *
284     *  @since 0.1.0
285     */
286    @API( status = STABLE, since = "0.1.0" )
287    public static final <T extends Number> Comparator<T> numberComparator()
288    {
289        final var retValue = (Comparator<T>) ( v1, v2) ->
290        {
291            //noinspection rawtypes
292            if( v1 instanceof final Comparable comparable )
293            {
294                @SuppressWarnings( "unchecked" )
295                final var result = signum( comparable.compareTo( v2 ) );
296                return result;
297            }
298            //noinspection NumericCastThatLosesPrecision
299            return (int) Math.signum( v1.doubleValue() - v2.doubleValue() );
300        };
301
302        //---* Done *----------------------------------------------------------
303        return retValue;
304    }   //  numberComparator()
305
306    /**
307     *  A comparator that compares arbitrary object types based on their String
308     *  representations.
309     *
310     *  @param  <T> The type to compare.
311     *  @param  stringConverter The instance of
312     *      {@link StringConverter}
313     *      that is used to get the String representation of the instances to
314     *      compare.
315     *  @return The comparator.
316     *
317     *  @since 0.1.0
318     */
319    @API( status = STABLE, since = "0.1.0" )
320    public static final <T> Comparator<T> stringBasedComparator( final StringConverter<T> stringConverter )
321    {
322        final var retValue = new StringBasedComparator<>( stringConverter );
323
324        //---* Done *----------------------------------------------------------
325        return retValue;
326    }   //  stringBasedComparator()
327}
328//  class Comparators
329
330/*
331 *  End of File
332 */