View Javadoc
1   /*
2    * junixsocket
3    *
4    * Copyright 2009-2024 Christian Kohlschütter
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.newsclub.net.unix;
19  
20  import java.io.Serializable;
21  import java.util.HashSet;
22  import java.util.Objects;
23  import java.util.Set;
24  
25  import org.eclipse.jdt.annotation.NonNullByDefault;
26  import org.eclipse.jdt.annotation.Nullable;
27  
28  /**
29   * A "named integer", usually used for constants.
30   *
31   * See the concrete implementations for usage.
32   *
33   * @author Christian Kohlschütter
34   */
35  @NonNullByDefault
36  public class NamedInteger implements Serializable {
37    private static final long serialVersionUID = 1L;
38  
39    /**
40     * The name.
41     */
42    private final String name; // NOPMD
43  
44    /**
45     * The ID value.
46     */
47    private final int id;
48  
49    /**
50     * Marks a subclass that provides a method {@code "public static T ofValue(int v)"} that allows
51     * casting an integer to this type via reflection.
52     */
53    public interface HasOfValue {
54      /* static <T extends NamedInteger> ofValue(int v); */
55    }
56  
57    /**
58     * Creates a new {@link NamedInteger} instance, without actually naming it. A name of "UNDEFINED"
59     * is used.
60     *
61     * @param id The value.
62     */
63    protected NamedInteger(int id) {
64      this("UNDEFINED", id);
65    }
66  
67    /**
68     * Creates a new {@link NamedInteger} instance.
69     *
70     * @param name The name.
71     * @param id The value.
72     */
73    protected NamedInteger(String name, int id) {
74      this.name = name;
75      this.id = id;
76    }
77  
78    /**
79     * Returns the name.
80     *
81     * @return The name.
82     */
83    public final String name() {
84      return name;
85    }
86  
87    /**
88     * Returns the value.
89     *
90     * @return The value.
91     */
92    public final int value() {
93      return id;
94    }
95  
96    @Override
97    public final String toString() {
98      return name() + "(" + id + ")";
99    }
100 
101   @Override
102   public final int hashCode() {
103     return Objects.hash(id);
104   }
105 
106   @Override
107   public final boolean equals(@Nullable Object obj) {
108     if (this == obj) {
109       return true;
110     } else if (obj == null) {
111       return false;
112     } else if (getClass() != obj.getClass()) {
113       return false;
114     }
115     NamedInteger other = (NamedInteger) obj;
116     return id == other.value();
117   }
118 
119   /**
120    * Ensures that the {@code VALUES} array is configured correctly.
121    *
122    * @param <T> The instance type.
123    * @param values The {@code VALUES} array.
124    * @return The verified {@code VALUES} array.
125    */
126   protected static final <T extends NamedInteger> T[] init(T[] values) {
127     Set<Integer> seenValues = new HashSet<>();
128     for (T val : values) {
129       if (!seenValues.add(val.value())) {
130         throw new IllegalStateException("Duplicate value: " + val.value());
131       }
132     }
133     return values;
134   }
135 
136   /**
137    * Constructor for "undefined" values.
138    *
139    * @param <T> The instance type.
140    */
141   @FunctionalInterface
142   protected interface UndefinedValueConstructor<T extends NamedInteger> {
143     /**
144      * Creates a new "undefined" value instance.
145      *
146      * @param id The value.
147      * @return The instance.
148      */
149     T newInstance(int id);
150   }
151 
152   /**
153    * Returns an instance given an integer value.
154    *
155    * @param <T> The instance type.
156    * @param values The {@code VALUES} array.
157    * @param constr The constructor for undefined values.
158    * @param v The value.
159    * @return The instance.
160    */
161   protected static final <T extends NamedInteger> T ofValue(T[] values,
162       UndefinedValueConstructor<T> constr, int v) {
163     for (T e : values) {
164       if (e.value() == v) {
165         return e;
166       }
167     }
168     return constr.newInstance(v);
169   }
170 }