1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.uwb.support.base;
18 
19 import java.util.ArrayList;
20 import java.util.EnumSet;
21 import java.util.List;
22 import java.util.Set;
23 
24 /**
25  * Flags backed by long value.
26  * If all the enum values fit in a integer, you can use
27  * {@link #toInt(Set)} and {@link #toEnumSet(int, Enum[])} safely. Otherwise, those methods will
28  * throw an {@link ArithmeticException} on overflow.
29  */
30 public interface FlagEnum {
getValue()31     long getValue();
32 
toInt(Set<E> enumSet)33     static <E extends Enum<E> & FlagEnum> int toInt(Set<E> enumSet) {
34         int value = 0;
35         for (E flag : enumSet) {
36             value |= Math.toIntExact(flag.getValue());
37         }
38         return value;
39     }
40 
toEnumSet(int flags, E[] values)41     static <E extends Enum<E> & FlagEnum> EnumSet<E> toEnumSet(int flags, E[] values) {
42         if (values.length == 0) {
43             throw new IllegalArgumentException("Empty FlagEnum");
44         }
45         List<E> flagList = new ArrayList<>();
46         for (E value : values) {
47             if ((flags & Math.toIntExact(value.getValue())) != 0) {
48                 flagList.add(value);
49             }
50         }
51         if (flagList.isEmpty()) {
52             Class<E> c = values[0].getDeclaringClass();
53             return EnumSet.noneOf(c);
54         } else {
55             return EnumSet.copyOf(flagList);
56         }
57     }
58 
toLong(Set<E> enumSet)59     static <E extends Enum<E> & FlagEnum> long toLong(Set<E> enumSet) {
60         long value = 0;
61         for (E flag : enumSet) {
62             value |= flag.getValue();
63         }
64         return value;
65     }
66 
longToEnumSet(long flags, E[] values)67     static <E extends Enum<E> & FlagEnum> EnumSet<E> longToEnumSet(long flags, E[] values) {
68         if (values.length == 0) {
69             throw new IllegalArgumentException("Empty FlagEnum");
70         }
71         List<E> flagList = new ArrayList<>();
72         for (E value : values) {
73             if ((flags & value.getValue()) != 0) {
74                 flagList.add(value);
75             }
76         }
77         if (flagList.isEmpty()) {
78             Class<E> c = values[0].getDeclaringClass();
79             return EnumSet.noneOf(c);
80         } else {
81             return EnumSet.copyOf(flagList);
82         }
83     }
84 }
85