001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- 002 * 003 * Copyright © 2025 microBean™. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 006 * the License. You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 011 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 012 * specific language governing permissions and limitations under the License. 013 */ 014package org.microbean.assign; 015 016import java.util.ArrayList; 017import java.util.Collection; 018import java.util.Collections; 019import java.util.List; 020import java.util.Map; 021import java.util.Map.Entry; 022 023import org.microbean.attributes.Attributes; 024 025import static java.util.HashMap.newHashMap; 026 027/** 028 * A utility class for working with commonly-used <dfn>qualifiers</dfn>. 029 * 030 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a> 031 * 032 * @see Attributes 033 */ 034public final class Qualifiers { 035 036 private static final Attributes QUALIFIER = Attributes.of("Qualifier"); 037 038 private static final List<Attributes> QUALIFIERS = List.of(QUALIFIER); 039 040 private static final Attributes ANY_QUALIFIER = Attributes.of("Any", QUALIFIERS); 041 042 private static final List<Attributes> ANY_QUALIFIERS = List.of(ANY_QUALIFIER); 043 044 private static final Attributes DEFAULT_QUALIFIER = Attributes.of("Default", QUALIFIERS); 045 046 private static final List<Attributes> DEFAULT_QUALIFIERS = List.of(DEFAULT_QUALIFIER); 047 048 private static final List<Attributes> ANY_AND_DEFAULT_QUALIFIERS = List.of(ANY_QUALIFIER, DEFAULT_QUALIFIER); 049 050 private static final Attributes PRIMORDIAL_QUALIFIER = Attributes.of("Primordial", QUALIFIERS); 051 052 private static final List<Attributes> PRIMORDIAL_QUALIFIERS = List.of(PRIMORDIAL_QUALIFIER); 053 054 private Qualifiers() { 055 super(); 056 } 057 058 /** 059 * Returns an unmodifiable {@link List} consisting solely of the unattributed <dfn>any qualifier</dfn> and the 060 * <dfn>default qualifier</dfn>. 061 * 062 * @return an unmodifiable {@link List} consisting solely of the unattributed any qualifier and the default qualifier; 063 * never {@code null} 064 * 065 * @see #anyQualifier() 066 * 067 * @see #defaultQualifier() 068 */ 069 public static final List<Attributes> anyAndDefaultQualifiers() { 070 return ANY_AND_DEFAULT_QUALIFIERS; 071 } 072 073 /** 074 * Returns the unattributed <dfn>any qualifier</dfn>. 075 * 076 * @return the <dfn>any qualifier</dfn>; never {@code null} 077 * 078 * @see #anyQualifiers() 079 */ 080 public static final Attributes anyQualifier() { 081 return ANY_QUALIFIER; 082 } 083 084 /** 085 * Returns {@code true} if and only if the supplied {@link Attributes} {@linkplain Attributes#equals(Object) is equal 086 * to} the unattributed {@linkplain #anyQualifier() any qualifier}. 087 * 088 * @param a an {@link Attributes}; must not be {@code null} 089 * 090 * @return {@code true} if and only if the supplied {@link Attributes} {@linkplain Attributes#equals(Object) is equal 091 * to} the unattributed {@linkplain #anyQualifier() any qualifier} 092 * 093 * @exception NullPointerException if {@code a} is {@code null} 094 */ 095 public static final boolean anyQualifier(final Attributes a) { 096 return ANY_QUALIFIER == a || anyQualifier().equals(a) && qualifier(a); 097 } 098 099 /** 100 * Returns an immutable {@link List} consisting solely of the unattributed <dfn>any qualifier</dfn>. 101 * 102 * @return an immutable {@link List}; never {@code null} 103 * 104 * @see #anyQualifier() 105 */ 106 public static final List<Attributes> anyQualifiers() { 107 return ANY_QUALIFIERS; 108 } 109 110 /** 111 * Returns the <dfn>default qualifier</dfn>. 112 * 113 * @return the <dfn>default qualifier</dfn>; never {@code null} 114 * 115 * @see #defaultQualifiers() 116 */ 117 public static final Attributes defaultQualifier() { 118 return DEFAULT_QUALIFIER; 119 } 120 121 /** 122 * Returns {@code true} if and only if the supplied {@link Attributes} {@linkplain 123 * Attributes#equals(Object) is equal to} the {@linkplain #defaultQualifier() default qualifier}. 124 * 125 * @param a an {@link Attributes}; must not be {@code null} 126 * 127 * @return {@code true} if and only if the supplied {@link Attributes} {@linkplain 128 * Attributes#equals(Object) is equal to} the {@linkplain #defaultQualifier() default qualifier} 129 * 130 * @exception NullPointerException if {@code a} is {@code null} 131 */ 132 public static final boolean defaultQualifier(final Attributes a) { 133 return DEFAULT_QUALIFIER == a || defaultQualifier().equals(a) && qualifier(a); 134 } 135 136 /** 137 * Returns an immutable {@link List} consisting solely of the <dfn>default qualifier</dfn>. 138 * 139 * @return an immutable {@link List}; never {@code null} 140 * 141 * @see #defaultQualifier() 142 */ 143 public static final List<Attributes> defaultQualifiers() { 144 return DEFAULT_QUALIFIERS; 145 } 146 147 /** 148 * Returns an {@link Attributes} that is {@linkplain Attributes#equals(Object) equal to} the supplied {@link 149 * Attributes}. 150 * 151 * <p>The returned {@link Attributes} may be the supplied {@link Attributes} or a different instance.</p> 152 * 153 * @param a an {@link Attributes}; must not be {@code null} 154 * 155 * @return an {@link Attributes} that is {@linkplain Attributes#equals(Object) equal to} the supplied {@link 156 * Attributes}; never {@code null} 157 * 158 * @exception NullPointerException if {@code a} is {@code null} 159 */ 160 public static final Attributes normalize(final Attributes a) { 161 return switch (a) { 162 case null -> throw new NullPointerException("a"); 163 case Attributes q when defaultQualifier(q) -> defaultQualifier(); 164 case Attributes q when QUALIFIER.equals(q) -> qualifier(); 165 default -> a; 166 }; 167 } 168 169 /** 170 * Returns an immutable {@link List} of {@link Attributes}s that is {@linkplain List#equals(Object) equal to} the 171 * supplied {@link List}. 172 * 173 * <p>The returned {@link List} may be the supplied {@link List} or a different instance.</p> 174 * 175 * @param list a {@link List} of {@link Attributes}s; must not be {@code null} 176 * 177 * @return an immutable {@link List} of {@link Attributes}s that is {@linkplain List#equals(Object) equal to} the 178 * supplied {@link List}; never {@code null} 179 * 180 * @exception NullPointerException if {@code list} is {@code null} 181 */ 182 public static final List<Attributes> normalize(final List<Attributes> list) { 183 return switch (list.size()) { 184 case 0 -> List.of(); 185 case 1 -> list.equals(defaultQualifiers()) ? defaultQualifiers() : List.copyOf(list); 186 default -> { 187 final List<Attributes> l = new ArrayList<>(list.size()); 188 for (final Attributes a : list) { 189 l.add(normalize(a)); 190 } 191 yield Collections.unmodifiableList(l); 192 } 193 }; 194 } 195 196 /** 197 * Returns the <dfn>primordial qualifier</dfn>. 198 * 199 * @return the <dfn>primordial qualifier</dfn>; never {@code null} 200 * 201 * @see #primordialQualifiers() 202 */ 203 public static final Attributes primordialQualifier() { 204 return PRIMORDIAL_QUALIFIER; 205 } 206 207 /** 208 * Returns {@code true} if and only if the supplied {@link Attributes} {@linkplain 209 * Attributes#equals(Object) is equal to} the {@linkplain #primordialQualifier() primordial qualifier}. 210 * 211 * @param a an {@link Attributes}; must not be {@code null} 212 * 213 * @return {@code true} if and only if the supplied {@link Attributes} {@linkplain 214 * Attributes#equals(Object) is equal to} the {@linkplain #primordialQualifier() primordial qualifier} 215 * 216 * @exception NullPointerException if {@code a} is {@code null} 217 */ 218 public static final boolean primordialQualifier(final Attributes a) { 219 return PRIMORDIAL_QUALIFIER == a || primordialQualifier().equals(a) && qualifier(a); 220 } 221 222 /** 223 * Returns an immutable {@link List} consisting solely of the <dfn>primordial qualifier</dfn>. 224 * 225 * @return an immutable {@link List}; never {@code null} 226 * 227 * @see #primordialQualifier() 228 */ 229 public static final List<Attributes> primordialQualifiers() { 230 return PRIMORDIAL_QUALIFIERS; 231 } 232 233 /** 234 * Returns the <dfn>qualifier</dfn> (meta-) qualifier. 235 * 236 * @return the <dfn>qualifier</dfn> (meta-) qualifier; never {@code null} 237 */ 238 public static final Attributes qualifier() { 239 return QUALIFIER; 240 } 241 242 /** 243 * Returns {@code true} if and only if the supplied {@link Attributes} is an {@link Attributes} that can be used to 244 * designate other {@link Attributes} as qualifiers. 245 * 246 * @param q an {@link Attributes}; must not be {@code null} 247 * 248 * @return {@code true} if and only if the supplied {@link Attributes} is an {@link Attributes} that can be used to 249 * designate other {@link Attributes} as qualifiers 250 * 251 * @exception NullPointerException if {@code q} is {@code null} 252 */ 253 public static final boolean qualifier(final Attributes q) { 254 return q.attributes().contains(qualifier()); 255 } 256 257 /** 258 * Returns an immutable {@link List} consisting solely of the <dfn>qualifier</dfn> (meta-) qualifier. 259 * 260 * @return an immutable {@link List}; never {@code null} 261 * 262 * @see #qualifier() 263 */ 264 public static final List<Attributes> qualifiers() { 265 return QUALIFIERS; 266 } 267 268 /** 269 * Returns an unmodifiable {@link List} consisting only of those {@link Attributes} in the supplied {@link 270 * Collection} that {@linkplain #qualifier(Attributes) are qualifiers}. 271 * 272 * @param c a {@link Collection} of {@link Attributes}s; must not be {@code null} 273 * 274 * @return an unmodifiable {@link List} consisting only of those {@link Attributes}s in the supplied {@link 275 * Collection} that {@linkplain #qualifier(Attributes) are qualifiers}; never {@code null} 276 * 277 * @exception NullPointerException if {@code c} is {@code null} 278 */ 279 public static final List<Attributes> qualifiers(final Collection<? extends Attributes> c) { 280 return switch (c) { 281 case Collection<?> c0 when c0.isEmpty() -> List.of(); 282 case Collection<?> c0 when c0.equals(defaultQualifiers()) -> defaultQualifiers(); 283 case Collection<?> c0 when c0.equals(anyAndDefaultQualifiers()) -> anyAndDefaultQualifiers(); 284 default ->{ 285 final ArrayList<Attributes> list = new ArrayList<>(c.size()); 286 for (final Attributes a : c) { 287 if (qualifier(a)) { 288 list.add(normalize(a)); 289 } 290 } 291 list.trimToSize(); 292 yield Collections.unmodifiableList(list); 293 } 294 }; 295 } 296 297}