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