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.attributes; 015 016import java.util.Arrays; 017import java.util.List; 018 019import java.lang.constant.ClassDesc; 020import java.lang.constant.DynamicConstantDesc; 021import java.lang.constant.MethodHandleDesc; 022import java.lang.constant.MethodTypeDesc; 023 024import java.util.Optional; 025 026import org.microbean.constant.Constables; 027 028import static java.lang.constant.ConstantDescs.BSM_INVOKE; 029import static java.lang.constant.ConstantDescs.CD_List; 030import static java.lang.constant.ConstantDescs.CD_Object; 031import static java.lang.constant.DirectMethodHandleDesc.Kind.STATIC; 032import static java.lang.constant.DirectMethodHandleDesc.Kind.VIRTUAL; 033 034/** 035 * A {@link Value} holding other {@link Value}s. 036 * 037 * @param <T> the type of the {@link Value}s 038 * 039 * @param value a non-{@code null} array of {@link Value}s 040 * 041 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a> 042 */ 043public final record ArrayValue<T extends Value<T>>(T[] value) implements Value<ArrayValue<T>> { 044 045 @SuppressWarnings("rawtypes") 046 private static final Value<?>[] EMPTY_VALUE_ARRAY = new Value[0]; 047 048 /** 049 * Creates a new {@link ArrayValue}. 050 * 051 * @param value a non-{@code null} array of {@link Value}s 052 * 053 * @exception NullPointerException if {@code value} is {@code null} 054 */ 055 public ArrayValue { 056 value = value.clone(); 057 } 058 059 @Override // Comparable<ArrayValue<T>> 060 public final int compareTo(final ArrayValue<T> other) { 061 if (other == null) { 062 return -1; 063 } else if (this.equals(other)) { 064 return 0; 065 } 066 return this.toString().compareTo(other.toString()); 067 } 068 069 @Override // Constable 070 public final Optional<DynamicConstantDesc<ArrayValue<T>>> describeConstable() { 071 final ClassDesc me = ClassDesc.of(this.getClass().getName()); 072 return Constables.describeConstable(Arrays.asList(this.value())) 073 .map(valueDesc -> DynamicConstantDesc.of(BSM_INVOKE, 074 MethodHandleDesc.ofMethod(STATIC, 075 me, 076 "of", 077 MethodTypeDesc.of(me, 078 CD_List)), 079 valueDesc)); 080 } 081 082 @Override // Record 083 public final boolean equals(final Object other) { 084 return 085 other == this || 086 // Follow java.lang.annotation.Annotation requirements. 087 other != null && other.getClass() == this.getClass() && Arrays.equals(this.value(), ((ArrayValue<?>)other).value()); 088 } 089 090 @Override // Record 091 public final int hashCode() { 092 // Follow java.lang.annotation.Annotation requirements. 093 return Arrays.hashCode(this.value()); 094 } 095 096 @Override // Record 097 public final String toString() { 098 return Arrays.asList(this.value()).toString(); 099 } 100 101 /** 102 * Returns the array of suitably-typed {@link Value}s this {@link ArrayValue} holds. 103 * 104 * <p>No reference to the returned array is kept.</p> 105 * 106 * @return a non-{@code null} array of suitably-typed {@link Value}s 107 */ 108 @Override // Record 109 public final T[] value() { 110 return this.value.clone(); 111 } 112 113 /** 114 * Returns an {@link ArrayValue} suitable for the supplied argument. 115 * 116 * @param values a non-{@code null} array of values 117 * 118 * @return a non-{@code null} {@link ArrayValue} 119 * 120 * @exception NullPointerException if {@code values} is {@code null} 121 * 122 * @see #of(Value[]) 123 */ 124 public static final ArrayValue<BooleanValue> of(final boolean... values) { 125 final var va = new BooleanValue[values.length]; 126 for (int i = 0; i < values.length; i++) { 127 va[i] = BooleanValue.of(values[i]); 128 } 129 return new ArrayValue<>(va); 130 } 131 132 /** 133 * Returns an {@link ArrayValue} suitable for the supplied argument. 134 * 135 * @param values a non-{@code null} array of values 136 * 137 * @return a non-{@code null} {@link ArrayValue} 138 * 139 * @exception NullPointerException if {@code values} is {@code null} 140 * 141 * @see #of(Value[]) 142 */ 143 public static final ArrayValue<ByteValue> of(final byte... values) { 144 final var va = new ByteValue[values.length]; 145 for (int i = 0; i < values.length; i++) { 146 va[i] = ByteValue.of(values[i]); 147 } 148 return new ArrayValue<>(va); 149 } 150 151 /** 152 * Returns an {@link ArrayValue} suitable for the supplied argument. 153 * 154 * @param values a non-{@code null} array of values 155 * 156 * @return a non-{@code null} {@link ArrayValue} 157 * 158 * @exception NullPointerException if {@code values} is {@code null} 159 * 160 * @see #of(Value[]) 161 */ 162 public static final ArrayValue<CharValue> of(final char... values) { 163 final var va = new CharValue[values.length]; 164 for (int i = 0; i < values.length; i++) { 165 va[i] = CharValue.of(values[i]); 166 } 167 return new ArrayValue<>(va); 168 } 169 170 /** 171 * Returns an {@link ArrayValue} suitable for the supplied argument. 172 * 173 * @param values a non-{@code null} array of values 174 * 175 * @return a non-{@code null} {@link ArrayValue} 176 * 177 * @exception NullPointerException if {@code values} is {@code null} 178 * 179 * @see #of(Value[]) 180 */ 181 public static final ArrayValue<DoubleValue> of(final double... values) { 182 final var va = new DoubleValue[values.length]; 183 for (int i = 0; i < values.length; i++) { 184 va[i] = DoubleValue.of(values[i]); 185 } 186 return new ArrayValue<>(va); 187 } 188 189 /** 190 * Returns an {@link ArrayValue} suitable for the supplied argument. 191 * 192 * @param values a non-{@code null} array of values 193 * 194 * @return a non-{@code null} {@link ArrayValue} 195 * 196 * @exception NullPointerException if {@code values} is {@code null} 197 * 198 * @see #of(Value[]) 199 */ 200 public static final ArrayValue<FloatValue> of(final float... values) { 201 final var va = new FloatValue[values.length]; 202 for (int i = 0; i < values.length; i++) { 203 va[i] = FloatValue.of(values[i]); 204 } 205 return new ArrayValue<>(va); 206 } 207 208 /** 209 * Returns an {@link ArrayValue} suitable for the supplied argument. 210 * 211 * @param values a non-{@code null} array of values 212 * 213 * @return a non-{@code null} {@link ArrayValue} 214 * 215 * @exception NullPointerException if {@code values} is {@code null} 216 * 217 * @see #of(Value[]) 218 */ 219 public static final ArrayValue<IntValue> of(final int... values) { 220 final var va = new IntValue[values.length]; 221 for (int i = 0; i < values.length; i++) { 222 va[i] = IntValue.of(values[i]); 223 } 224 return new ArrayValue<>(va); 225 } 226 227 /** 228 * Returns an {@link ArrayValue} suitable for the supplied argument. 229 * 230 * @param values a non-{@code null} array of values 231 * 232 * @return a non-{@code null} {@link ArrayValue} 233 * 234 * @exception NullPointerException if {@code values} is {@code null} 235 * 236 * @see #of(Value[]) 237 */ 238 public static final ArrayValue<LongValue> of(final long... values) { 239 final var va = new LongValue[values.length]; 240 for (int i = 0; i < values.length; i++) { 241 va[i] = LongValue.of(values[i]); 242 } 243 return new ArrayValue<>(va); 244 } 245 246 /** 247 * Returns an {@link ArrayValue} suitable for the supplied argument. 248 * 249 * @param values a non-{@code null} array of values 250 * 251 * @return a non-{@code null} {@link ArrayValue} 252 * 253 * @exception NullPointerException if {@code values} is {@code null} 254 * 255 * @see #of(Value[]) 256 */ 257 public static final ArrayValue<ShortValue> of(final short... values) { 258 final var va = new ShortValue[values.length]; 259 for (int i = 0; i < values.length; i++) { 260 va[i] = ShortValue.of(values[i]); 261 } 262 return new ArrayValue<>(va); 263 } 264 265 /** 266 * Returns an {@link ArrayValue} suitable for the supplied argument. 267 * 268 * @param values a non-{@code null} array of values 269 * 270 * @return a non-{@code null} {@link ArrayValue} 271 * 272 * @exception NullPointerException if {@code values} is {@code null} 273 * 274 * @see #of(Value[]) 275 */ 276 public static final ArrayValue<ClassValue> of(final Class<?>... values) { 277 final var va = new ClassValue[values.length]; 278 for (int i = 0; i < values.length; i++) { 279 va[i] = ClassValue.of(values[i]); 280 } 281 return new ArrayValue<>(va); 282 } 283 284 /** 285 * Returns an {@link ArrayValue} suitable for the supplied argument. 286 * 287 * @param values a non-{@code null} array of values 288 * 289 * @return a non-{@code null} {@link ArrayValue} 290 * 291 * @exception NullPointerException if {@code values} is {@code null} 292 * 293 * @see #of(Value[]) 294 */ 295 public static final ArrayValue<StringValue> of(final String... values) { 296 final var va = new StringValue[values.length]; 297 for (int i = 0; i < values.length; i++) { 298 va[i] = StringValue.of(values[i]); 299 } 300 return new ArrayValue<>(va); 301 } 302 303 /** 304 * Returns an {@link ArrayValue} suitable for the supplied argument. 305 * 306 * @param <T> the type of {@link Value} held by the returned {@link ArrayValue} 307 * 308 * @param value a non-{@code null} {@link List} of suitably-typed {@link Value}s 309 * 310 * @return a non-{@code null} {@link ArrayValue} 311 * 312 * @exception NullPointerException if {@code value} is {@code null} 313 * 314 * @see #of(Value[]) 315 */ 316 @SuppressWarnings("unchecked") 317 // Called by #describeConstable() 318 public static final <T extends Value<T>> ArrayValue<T> of(final List<T> value) { 319 return of(value.toArray((T[])EMPTY_VALUE_ARRAY)); 320 } 321 322 /** 323 * Returns an {@link ArrayValue} suitable for the supplied argument. 324 * 325 * @param <T> the type of {@link Value} held by the returned {@link ArrayValue} 326 * 327 * @param value a non-{@code null} array of suitably-typed {@link Value}s 328 * 329 * @return a non-{@code null} {@link ArrayValue} 330 * 331 * @exception NullPointerException if {@code value} is {@code null} 332 */ 333 public static final <T extends Value<T>> ArrayValue<T> of(final T[] value) { 334 return new ArrayValue<>(value); 335 } 336 337}