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 }