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.juneau.commons.collections;
018
019import static java.util.Collections.*;
020import static org.apache.juneau.commons.utils.ClassUtils.*;
021import static org.apache.juneau.commons.utils.Shorts.*;
022
023import java.lang.reflect.*;
024import java.util.*;
025import java.util.function.*;
026
027/**
028 * A fluent builder for constructing {@link Set} instances with various configuration options.
029 *
030 * <p>
031 * This builder provides a flexible and type-safe way to construct sets with support for adding elements,
032 * collections, arrays, sorting, and applying modifiers like unmodifiable or sparse modes. Sets automatically
033 * handle duplicates - adding the same element multiple times will result in only one occurrence in the final set.
034 *
035 * <h5 class='section'>Features:</h5>
036 * <ul class='spaced-list'>
037 *    <li>Fluent API - all methods return <c>this</c> for method chaining
038 *    <li>Multiple add methods - single elements, varargs, collections, arrays
039 *    <li>Arbitrary input support - automatic type conversion with {@link #addAny(Object...)}
040 *    <li>Conditional adding - {@link #addIf(boolean, Object)} for conditional elements
041 *    <li>Sorting support - natural order or custom {@link Comparator}
042 *    <li>Sparse mode - return <jk>null</jk> for empty sets
043 *    <li>Unmodifiable mode - create immutable sets
044 *    <li>Filtering support - exclude unwanted elements via {@link #filtered()} or {@link #filtered(Predicate)}
045 *    <li>Custom conversion functions - type conversion via {@link #elementFunction(Function)}
046 *    <li>Automatic deduplication - duplicate elements are automatically removed
047 * </ul>
048 *
049 * <h5 class='section'>Examples:</h5>
050 * <p class='bjava'>
051 *    <jc>// Basic usage</jc>
052 *    Set&lt;String&gt; <jv>set</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>)
053 *       .add(<js>"apple"</js>, <js>"banana"</js>, <js>"cherry"</js>)
054 *       .build();
055 *
056 *    <jc>// Automatic deduplication</jc>
057 *    Set&lt;Integer&gt; <jv>unique</jv> = Sets.<jsm>create</jsm>(Integer.<jk>class</jk>)
058 *       .add(1, 2, 3, 2, 1)  <jc>// Duplicates ignored</jc>
059 *       .build();  <jc>// Contains: 1, 2, 3</jc>
060 *
061 *    <jc>// With sorting</jc>
062 *    Set&lt;String&gt; <jv>sorted</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>)
063 *       .add(<js>"zebra"</js>, <js>"apple"</js>, <js>"banana"</js>)
064 *       .sorted()
065 *       .build();  <jc>// Returns TreeSet in natural order</jc>
066 *
067 *    <jc>// Conditional elements</jc>
068 *    Set&lt;String&gt; <jv>features</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>)
069 *       .add(<js>"basic"</js>)
070 *       .addIf(<jv>hasPremium</jv>, <js>"premium"</js>)
071 *       .addIf(<jv>hasEnterprise</jv>, <js>"enterprise"</js>)
072 *       .build();
073 *
074 *    <jc>// Immutable set</jc>
075 *    Set&lt;String&gt; <jv>immutable</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>)
076 *       .add(<js>"read"</js>, <js>"only"</js>)
077 *       .unmodifiable()
078 *       .build();
079 *
080 *    <jc>// From multiple sources</jc>
081 *    Set&lt;Integer&gt; <jv>existing</jv> = Set.of(1, 2, 3);
082 *    Set&lt;Integer&gt; <jv>combined</jv> = Sets.<jsm>create</jsm>(Integer.<jk>class</jk>)
083 *       .addAll(<jv>existing</jv>)
084 *       .add(4, 5, 6)
085 *       .build();
086 *
087 *    <jc>// Sparse mode - returns null when empty</jc>
088 *    Set&lt;String&gt; <jv>maybeNull</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>)
089 *       .sparse()
090 *       .build();  <jc>// Returns null, not empty set</jc>
091 *
092 *    <jc>// FluentSet wrapper - use buildFluent()</jc>
093 *    FluentSet&lt;String&gt; <jv>fluent</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>)
094 *       .add(<js>"one"</js>, <js>"two"</js>)
095 *       .buildFluent();
096 *
097 *    <jc>// FilteredSet - use buildFiltered()</jc>
098 *    FilteredSet&lt;Integer&gt; <jv>filtered</jv> = Sets.<jsm>create</jsm>(Integer.<jk>class</jk>)
099 *       .filtered(v -&gt; v &gt; 0)
100 *       .add(5)
101 *       .add(-1)  <jc>// Filtered out</jc>
102 *       .buildFiltered();
103 * </p>
104 *
105 * <h5 class='section'>Thread Safety:</h5>
106 * <p>
107 * This class is <b>not thread-safe</b>. Each builder instance should be used by a single thread or
108 * properly synchronized.
109 *
110 * <h5 class='section'>See Also:</h5><ul>
111 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsCollections">Collections Package</a>
112 *    <li class='jc'>{@link Lists}
113 *    <li class='jc'>{@link Maps}
114 * </ul>
115 *
116 * @param <E> The element type.
117 */
118@SuppressWarnings({
119   "java:S1168", // build() and buildFiltered() return null when sparse() is set and the set is empty
120   "java:S1192", // Duplicated literals (argument/property names) read more clearly inline than as constants
121   "java:S3740", // Raw Set/Iterable types used in utility methods where element type is not statically known
122   "unchecked" // Element casts such as (E)o in the builder are guarded by the builder's element-type contract
123})
124public class Sets<E> {
125
126   /**
127    * Static creator.
128    *
129    * @param <E> The element type.
130    * @param elementType The element type. Must not be <jk>null</jk>.
131    * @return A new builder.
132    */
133   public static <E> Sets<E> create(Class<E> elementType) {
134      return new Sets<>(reqnn("elementType", elementType));
135   }
136
137   private Set<E> set;
138   private boolean unmodifiable;
139   private boolean sparse;
140   private boolean concurrent;
141   private boolean ordered = false;
142
143   private Comparator<E> comparator;
144   private Predicate<E> filter;
145   private Class<E> elementType;
146   private Function<Object,E> elementFunction;
147
148   /**
149    * Constructor.
150    *
151    * @param elementType The element type. Must not be <jk>null</jk>.
152    */
153   public Sets(Class<E> elementType) {
154      this.elementType = reqnn("elementType", elementType);
155   }
156
157   /**
158    * Adds a single value to this set.
159    *
160    * <p>
161    * Note: Filtering is applied at build time, not when adding elements.
162    *
163    * @param value The value to add to this set.
164    * @return This object.
165    */
166   public Sets<E> add(E value) {
167      if (set == null) {
168         if (ordered)
169            set = new LinkedHashSet<>();
170         else if (nn(comparator))
171            set = new TreeSet<>(comparator);
172         else
173            set = new HashSet<>();
174      }
175      set.add(value);
176      return this;
177   }
178
179   /**
180    * Adds multiple values to this set.
181    *
182    * @param values The values to add to this set.
183    * @return This object.
184    */
185   public Sets<E> add(E...values) {
186      reqnn("values", values);
187      for (var v : values)
188         add(v);
189      return this;
190   }
191
192   /**
193    * Appends the contents of the specified collection into this set.
194    *
195    * <p>
196    * This is a no-op if the value is <jk>null</jk>.
197    *
198    * @param value The collection to add to this set.
199    * @return This object.
200    */
201   public Sets<E> addAll(Collection<E> value) {
202      if (nn(value)) {
203         if (set == null) {
204            if (ordered)
205               set = new LinkedHashSet<>(value);
206            else if (nn(comparator))
207               set = new TreeSet<>(comparator);
208            else
209               set = new HashSet<>(value);
210         } else {
211            set.addAll(value);
212         }
213      }
214      return this;
215   }
216
217   /**
218    * Adds arbitrary values to this set.
219    *
220    * <p>
221    * Objects can be any of the following:
222    * <ul>
223    *    <li>The same type or convertible to the element type of this set.
224    *    <li>Collections or arrays of anything on this set.
225    *    <li>JSON array strings parsed and convertible to the element type of this set.
226    * </ul>
227    *
228    * @param values The values to add.
229    * @return This object.
230    */
231   @SuppressWarnings({
232      "java:S3776" // Cognitive complexity acceptable for adding elements of various types
233   })
234   public Sets<E> addAny(Object...values) {
235      if (nn(values)) {
236         for (var o : values) {
237            if (nn(o)) {
238               if (o instanceof Collection<?> o2) {
239                  o2.forEach(this::addAny);
240               } else if (isArray(o)) {
241                  for (var i = 0; i < Array.getLength(o); i++)
242                     addAny(Array.get(o, i));
243               } else if (elementType.isInstance(o)) {
244                  add(elementType.cast(o));
245               } else {
246                  E converted = convertElement(o);
247                  if (converted != null) {
248                     add(converted);
249                  } else {
250                     throw rex("Object of type %s could not be converted to type %s", cn(o), cn(elementType));
251                  }
252               }
253            }
254         }
255      }
256      return this;
257   }
258
259   /**
260    * Adds a value to this set if the specified flag is true.
261    *
262    * @param flag The flag.
263    * @param value The value.
264    * @return This object.
265    */
266   public Sets<E> addIf(boolean flag, E value) {
267      if (flag)
268         add(value);
269      return this;
270   }
271
272   /**
273    * Adds entries to this set via JSON array strings.
274    *
275    * @param values The JSON array strings to parse and add to this set.
276    * @return This object.
277    */
278   public Sets<E> addJson(String...values) {
279      return addAny((Object[])values);
280   }
281
282   /**
283    * Builds the set.
284    *
285    * <p>
286    * Applies filtering, sorting, ordering, concurrent, unmodifiable, and sparse options.
287    *
288    * <p>
289    * Set type selection:
290    * <ul>
291    *    <li>If {@link #sorted()} is set: Uses {@link TreeSet} (or synchronized TreeSet if concurrent)
292    *    <li>If {@link #ordered()} is set: Uses {@link LinkedHashSet} (or synchronized LinkedHashSet if concurrent)
293    *    <li>Otherwise: Uses {@link HashSet} (or synchronized HashSet if concurrent)
294    * </ul>
295    *
296    * <p>
297    * If filtering is applied, the result is wrapped in a {@link FilteredSet}.
298    *
299    * @return The built set, or {@code null} if {@link #sparse()} is set and the set is empty.
300    */
301   public Set<E> build() {
302      if (sparse && ie(set))
303         return null;
304
305      Set<E> set2 = null;
306
307      if (ordered) {
308         set2 = new LinkedHashSet<>();
309      } else if (nn(comparator)) {
310         set2 = new TreeSet<>(comparator);
311      } else {
312         set2 = new HashSet<>();
313      }
314
315      if (concurrent)
316         set2 = synchronizedSet(set2);
317
318      if (nn(filter) || nn(elementFunction)) {
319         var set3b = FilteredSet.create(elementType);
320         if (nn(filter))
321            set3b.filter(filter);
322         if (nn(elementFunction))
323            set3b.elementFunction(elementFunction);
324         set2 = set3b.inner(set2).build();
325      }
326
327      if (nn(set))
328         set2.addAll(set);
329
330      if (unmodifiable)
331         set2 = unmodifiableSet(set2);
332
333      return set2;
334   }
335
336   /**
337    * Builds the set and wraps it in a {@link FluentSet}.
338    *
339    * <p>
340    * This is a convenience method that calls {@link #build()} and wraps the result in a {@link FluentSet}.
341    *
342    * <h5 class='section'>Example:</h5>
343    * <p class='bjava'>
344    *    <jk>import static</jk> org.apache.juneau.commons.utils.CollectionUtils.*;
345    *
346    *    FluentSet&lt;String&gt; <jv>set</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>)
347    *       .add(<js>"one"</js>, <js>"two"</js>)
348    *       .buildFluent();
349    * </p>
350    *
351    * @return The built set wrapped in a {@link FluentSet}, or {@code null} if {@link #sparse()} is set and the set is empty.
352    */
353   public FluentSet<E> buildFluent() {
354      Set<E> result = build();
355      return result == null ? null : new FluentSet<>(result);
356   }
357
358   /**
359    * Builds the set as a {@link FilteredSet}.
360    *
361    * <p>
362    * Set type selection:
363    * <ul>
364    *    <li>If {@link #sorted()} is set: Uses {@link TreeSet} (or synchronized TreeSet if concurrent)
365    *    <li>If {@link #ordered()} is set: Uses {@link LinkedHashSet} (or synchronized LinkedHashSet if concurrent)
366    *    <li>Otherwise: Uses {@link HashSet} (or synchronized HashSet if concurrent)
367    * </ul>
368    *
369    * <h5 class='section'>Example:</h5>
370    * <p class='bjava'>
371    *    <jk>import static</jk> org.apache.juneau.commons.utils.CollectionUtils.*;
372    *
373    *    FilteredSet&lt;Integer&gt; <jv>set</jv> = Sets.<jsm>create</jsm>(Integer.<jk>class</jk>)
374    *       .filtered(v -&gt; v != <jk>null</jk> &amp;&amp; v &gt; 0)
375    *       .add(5)
376    *       .add(-1)  <jc>// Will be filtered out</jc>
377    *       .buildFiltered();
378    * </p>
379    *
380    * <p>
381    * Note: If {@link #unmodifiable()} is set, the returned set will be wrapped in an unmodifiable view,
382    * which may cause issues if the FilteredSet tries to modify it internally. It's recommended to avoid
383    * using {@link #unmodifiable()} when calling this method.
384    *
385    * @return The built set as a {@link FilteredSet}, or {@code null} if {@link #sparse()} is set and the set is empty.
386    */
387   public FilteredSet<E> buildFiltered() {
388      var s = build();
389      if (s == null)  // sparse mode and empty
390         return null;
391      if (s instanceof FilteredSet<E> s2)
392         return s2;
393      // Note that if unmodifiable is true, 's' will be unmodifiable and will cause an error if you try
394      // to insert a value from within FilteredSet.
395      return FilteredSet.create(elementType).inner(s).build();
396   }
397
398   /**
399    * Sets the element conversion function for converting elements in {@link #addAny(Object...)}.
400    *
401    * <p>
402    * The function is applied to each element when adding elements in {@link #addAny(Object...)}.
403    *
404    * @param elementFunction The function to convert elements. Must not be <jk>null</jk>.
405    * @return This object.
406    */
407   public Sets<E> elementFunction(Function<Object,E> elementFunction) {
408      this.elementFunction = reqnn("elementFunction", elementFunction);
409      return this;
410   }
411
412   /**
413    * Specifies the element type on this list.
414    *
415    * @param value The element type. Must not be <jk>null</jk>.
416    * @return This object.
417    */
418   public Sets<E> elementType(Class<E> value) {
419      elementType = reqnn("value", value);
420      return this;
421   }
422
423   /**
424    * Applies a default filter that excludes common "empty" or "unset" values from being added to the set.
425    *
426    * <p>
427    * The following values are filtered out:
428    * <ul>
429    *    <li>{@code null}
430    *    <li>{@link Boolean#FALSE}
431    *    <li>Numbers with {@code intValue() == -1}
432    *    <li>Empty arrays
433    *    <li>Empty {@link Map Maps}
434    *    <li>Empty {@link Collection Collections}
435    * </ul>
436    *
437    * <h5 class='section'>Example:</h5>
438    * <p class='bjava'>
439    *    <jk>import static</jk> org.apache.juneau.commons.utils.CollectionUtils.*;
440    *
441    *    Set&lt;Object&gt; <jv>set</jv> = Sets.<jsm>create</jsm>(Object.<jk>class</jk>)
442    *       .filtered()
443    *       .add(<js>"name"</js>)
444    *       .add(-1)              <jc>// Filtered out at build time</jc>
445    *       .add(<jk>false</jk>)     <jc>// Filtered out at build time</jc>
446    *       .add(<jk>new</jk> String[0]) <jc>// Filtered out at build time</jc>
447    *       .build();
448    * </p>
449    *
450    * @return This object.
451    */
452   public Sets<E> filtered() {
453      // @formatter:off
454      return filtered(v -> ! (
455         v == null
456         || (v instanceof Boolean v2 && v2.equals(false))
457         || (v instanceof Number v3 && v3.intValue() == -1)
458         || (isArray(v) && Array.getLength(v) == 0)
459         || (v instanceof Map v2 && v2.isEmpty())
460         || (v instanceof Collection v3 && v3.isEmpty())
461         ));
462      // @formatter:on
463   }
464
465   /**
466    * Applies a filter predicate to elements when building the set.
467    *
468    * <p>
469    * The filter receives the element value. Elements where the predicate returns
470    * {@code true} will be kept; elements where it returns {@code false} will be filtered out.
471    *
472    * <p>
473    * This method can be called multiple times. When called multiple times, all filters are combined
474    * using AND logic - an element must pass all filters to be kept in the set.
475    *
476    * <p>
477    * Note: Filtering is applied at build time, not when adding elements.
478    *
479    * <h5 class='section'>Example:</h5>
480    * <p class='bjava'>
481    *    <jk>import static</jk> org.apache.juneau.commons.utils.CollectionUtils.*;
482    *
483    *    <jc>// Keep only non-null, positive integers</jc>
484    *    Set&lt;Integer&gt; <jv>set</jv> = Sets.<jsm>create</jsm>(Integer.<jk>class</jk>)
485    *       .filtered(v -&gt; v != <jk>null</jk> &amp;&amp; v &gt; 0)
486    *       .add(5)
487    *       .add(-1)     <jc>// Filtered out at build time</jc>
488    *       .add(<jk>null</jk>) <jc>// Filtered out at build time</jc>
489    *       .build();
490    *
491    *    <jc>// Multiple filters combined with AND</jc>
492    *    Set&lt;Integer&gt; <jv>set2</jv> = Sets.<jsm>create</jsm>(Integer.<jk>class</jk>)
493    *       .filtered(v -&gt; v != <jk>null</jk>)           <jc>// First filter</jc>
494    *       .filtered(v -&gt; v &gt; 0)                    <jc>// Second filter (ANDed with first)</jc>
495    *       .filtered(v -&gt; v &lt; 100);                  <jc>// Third filter (ANDed with previous)</jc>
496    *       .add(5)
497    *       .add(150)  <jc>// Filtered out (not &lt; 100)</jc>
498    *       .add(-1)   <jc>// Filtered out (not &gt; 0)</jc>
499    *       .build();
500    * </p>
501    *
502    * @param filter The filter predicate. Must not be <jk>null</jk>.
503    * @return This object.
504    */
505   public Sets<E> filtered(Predicate<E> filter) {
506      Predicate<E> newFilter = reqnn("filter", filter);
507      if (this.filter == null)
508         this.filter = newFilter;
509      else
510         this.filter = this.filter.and(newFilter);
511      return this;
512   }
513
514   /**
515    * Converts the set into a {@link SortedSet}.
516    *
517    * <p>
518    * Note: If {@link #ordered()} was previously called, calling this method will override it.
519    * The last method called ({@link #ordered()} or {@link #sorted()}) determines the final set type.
520    *
521    * @return This object.
522    */
523   public Sets<E> sorted() {
524      return sorted((Comparator<E>)Comparator.naturalOrder());
525   }
526
527   /**
528    * Converts the set into a {@link SortedSet} using the specified comparator.
529    *
530    * <p>
531    * Note: If {@link #ordered()} was previously called, calling this method will override it.
532    * The last method called ({@link #ordered()} or {@link #sorted()}) determines the final set type.
533    *
534    * @param comparator The comparator to use for sorting. Must not be <jk>null</jk>.
535    * @return This object.
536    */
537   public Sets<E> sorted(Comparator<E> comparator) {
538      this.comparator = reqnn("comparator", comparator);
539      ordered = false;
540      return this;
541   }
542
543   /**
544    * When specified, the {@link #build()} method will return <jk>null</jk> if the set is empty.
545    *
546    * <p>
547    * Otherwise {@link #build()} will never return <jk>null</jk>.
548    *
549    * @return This object.
550    */
551   public Sets<E> sparse() {
552      sparse = true;
553      return this;
554   }
555
556
557   /**
558    * When specified, {@link #build()} will return an unmodifiable set.
559    *
560    * @return This object.
561    */
562   public Sets<E> unmodifiable() {
563      unmodifiable = true;
564      return this;
565   }
566
567   /**
568    * When specified, {@link #build()} will return a thread-safe synchronized set.
569    *
570    * <p>
571    * The thread-safety implementation depends on other settings:
572    * <ul>
573    *    <li>If {@link #sorted()} is set: Uses synchronized {@link TreeSet}
574    *    <li>If {@link #ordered()} is set: Uses synchronized {@link LinkedHashSet}
575    *    <li>Otherwise: Uses synchronized {@link HashSet}
576    * </ul>
577    *
578    * <p>
579    * This is useful when the set needs to be accessed from multiple threads.
580    *
581    * <h5 class='section'>Example:</h5>
582    * <p class='bjava'>
583    *    <jc>// Create a thread-safe set using synchronized HashSet</jc>
584    *    Set&lt;String&gt; <jv>set</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>)
585    *       .add(<js>"one"</js>, <js>"two"</js>)
586    *       .concurrent()
587    *       .build();
588    *
589    *    <jc>// Create a thread-safe ordered set</jc>
590    *    Set&lt;String&gt; <jv>set2</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>)
591    *       .ordered()
592    *       .concurrent()
593    *       .add(<js>"one"</js>)
594    *       .build();
595    * </p>
596    *
597    * @return This object.
598    */
599   public Sets<E> concurrent() {
600      concurrent = true;
601      return this;
602   }
603
604   /**
605    * Sets whether {@link #build()} should return a thread-safe synchronized set.
606    *
607    * <p>
608    * The thread-safety implementation depends on other settings:
609    * <ul>
610    *    <li>If {@link #sorted()} is set: Uses synchronized {@link TreeSet}
611    *    <li>If {@link #ordered()} is set: Uses synchronized {@link LinkedHashSet}
612    *    <li>Otherwise: Uses synchronized {@link HashSet}
613    * </ul>
614    *
615    * <p>
616    * This is useful when the set needs to be accessed from multiple threads.
617    *
618    * <h5 class='section'>Example:</h5>
619    * <p class='bjava'>
620    *    <jc>// Conditionally create a thread-safe set</jc>
621    *    Set&lt;String&gt; <jv>set</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>)
622    *       .add(<js>"one"</js>, <js>"two"</js>)
623    *       .concurrent(<jv>needsThreadSafety</jv>)
624    *       .build();
625    * </p>
626    *
627    * @param value Whether to make the set thread-safe.
628    * @return This object.
629    */
630   public Sets<E> concurrent(boolean value) {
631      concurrent = value;
632      return this;
633   }
634
635   /**
636    * When specified, {@link #build()} will use a {@link LinkedHashSet} to preserve insertion order.
637    *
638    * <p>
639    * If not specified, a {@link HashSet} is used by default (no guaranteed order).
640    *
641    * <p>
642    * Note: If {@link #sorted()} was previously called, calling this method will override it.
643    * The last method called ({@link #ordered()} or {@link #sorted()}) determines the final set type.
644    *
645    * <h5 class='section'>Example:</h5>
646    * <p class='bjava'>
647    *    <jc>// Create an ordered set (preserves insertion order)</jc>
648    *    Set&lt;String&gt; <jv>set</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>)
649    *       .ordered()
650    *       .add(<js>"one"</js>)
651    *       .add(<js>"two"</js>)
652    *       .build();
653    * </p>
654    *
655    * @return This object.
656    */
657   public Sets<E> ordered() {
658      return ordered(true);
659   }
660
661   /**
662    * Sets whether {@link #build()} should use a {@link LinkedHashSet} to preserve insertion order.
663    *
664    * <p>
665    * If <c>false</c> (default), a {@link HashSet} is used (no guaranteed order).
666    * If <c>true</c>, a {@link LinkedHashSet} is used (preserves insertion order).
667    *
668    * <p>
669    * Note: If {@link #sorted()} was previously called, calling this method with <c>true</c> will override it.
670    * The last method called ({@link #ordered()} or {@link #sorted()}) determines the final set type.
671    *
672    * <h5 class='section'>Example:</h5>
673    * <p class='bjava'>
674    *    <jc>// Conditionally create an ordered set</jc>
675    *    Set&lt;String&gt; <jv>set</jv> = Sets.<jsm>create</jsm>(String.<jk>class</jk>)
676    *       .ordered(<jv>preserveOrder</jv>)
677    *       .add(<js>"one"</js>)
678    *       .build();
679    * </p>
680    *
681    * @param value Whether to preserve insertion order.
682    * @return This object.
683    */
684   public Sets<E> ordered(boolean value) {
685      ordered = value;
686      if (ordered)
687         comparator = null;
688      return this;
689   }
690
691   /**
692    * Converts an element object to the element type.
693    *
694    * @param o The object to convert.
695    * @return The converted element, or <jk>null</jk> if conversion is not possible.
696    */
697   private E convertElement(Object o) {
698      if (elementType.isInstance(o))
699         return (E)o;
700      if (nn(elementFunction))
701         return elementFunction.apply(o);
702      return null;
703   }
704}