001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.osm; 003 004import static java.util.Comparator.comparing; 005import static java.util.Comparator.comparingInt; 006 007import java.util.Comparator; 008import java.util.HashMap; 009import java.util.Map; 010import java.util.function.Function; 011 012import org.openstreetmap.josm.tools.AlphanumComparator; 013 014/** 015 * Comparators for comparing {@link IPrimitive}. 016 * @since 13803 017 */ 018public final class PrimitiveComparator { 019 020 /** 021 * Returns a comparator comparing primitives by their name using {@link DefaultNameFormatter}. 022 * 023 * {@linkplain DefaultNameFormatter#format(IPrimitive) Formatted names} are cached. 024 * 025 * @return a comparator comparing primitives by their name using {@link DefaultNameFormatter} 026 */ 027 public static Comparator<IPrimitive> comparingNames() { 028 return doComparingNames(); 029 } 030 031 static <T extends IPrimitive> Comparator<T> doComparingNames() { 032 final Comparator<String> digitsLast = comparing(str -> !str.isEmpty() && Character.isDigit(str.charAt(0)) ? 1 : 0); 033 return comparing(memoize(DefaultNameFormatter.getInstance()::format), 034 digitsLast.thenComparing(AlphanumComparator.getInstance())); 035 } 036 037 /** 038 * Returns a comparator comparing primitives by their {@linkplain IPrimitive#getUniqueId unique id}. 039 * 040 * @return a comparator comparing primitives by their {@linkplain IPrimitive#getUniqueId unique id}. 041 */ 042 public static Comparator<IPrimitive> comparingUniqueId() { 043 return doComparingUniqueId(); 044 } 045 046 static <T extends IPrimitive> Comparator<T> doComparingUniqueId() { 047 return comparing(IPrimitive::getUniqueId); 048 } 049 050 /** 051 * Returns a comparator ordering the primitives by type in the order NODE, WAY, RELATION 052 * 053 * @return a comparator ordering the primitives by type in the order NODE, WAY, RELATION 054 */ 055 public static Comparator<IPrimitive> orderingNodesWaysRelations() { 056 return doOrderingNodesWaysRelations(); 057 } 058 059 static <T extends IPrimitive> Comparator<T> doOrderingNodesWaysRelations() { 060 return comparingInt(osm -> osm.getType().ordinal()); 061 } 062 063 /** 064 * Returns a comparator ordering the primitives by type in the order WAY, RELATION, NODE 065 * 066 * @return a comparator ordering the primitives by type in the order WAY, RELATION, NODE 067 */ 068 public static Comparator<IPrimitive> orderingWaysRelationsNodes() { 069 return doOrderingWaysRelationsNodes(); 070 } 071 072 static <T extends IPrimitive> Comparator<T> doOrderingWaysRelationsNodes() { 073 return comparingInt(osm -> { 074 switch (osm.getType()) { 075 case WAY: 076 return 1; 077 case RELATION: 078 return 2; 079 case NODE: 080 return 3; 081 default: 082 throw new IllegalStateException(); 083 } 084 }); 085 } 086 087 /** 088 * Returns a comparator ordering the primitives by type in the order RELATION, WAY, NODE 089 * 090 * @return a comparator ordering the primitives by type in the order RELATION, WAY, NODE 091 */ 092 public static Comparator<IPrimitive> orderingRelationsWaysNodes() { 093 return doOrderingRelationsWaysNodes(); 094 } 095 096 static <T extends IPrimitive> Comparator<T> doOrderingRelationsWaysNodes() { 097 return comparingInt(osm -> { 098 switch (osm.getType()) { 099 case RELATION: 100 return 1; 101 case WAY: 102 return 2; 103 case NODE: 104 return 3; 105 default: 106 throw new IllegalStateException(); 107 } 108 }); 109 } 110 111 private static <T, R> Function<T, R> memoize(Function<T, R> base) { 112 final Map<T, R> cache = new HashMap<>(); 113 return t -> cache.computeIfAbsent(t, base); 114 } 115 116 private PrimitiveComparator() { 117 } 118}