1fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar/* 2fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Copyright (C) 2016 The Android Open Source Project 3fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 4fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Licensed under the Apache License, Version 2.0 (the "License"); 5fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * you may not use this file except in compliance with the License. 6fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * You may obtain a copy of the License at 7fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 8fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * http://www.apache.org/licenses/LICENSE-2.0 9fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 10fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Unless required by applicable law or agreed to in writing, software 11fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * distributed under the License is distributed on an "AS IS" BASIS, 12fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * See the License for the specific language governing permissions and 14fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * limitations under the License. 15fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar */ 16fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 17fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar#ifndef STAGEFRIGHT_FOUNDATION_FLAGGED_H_ 18fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar#define STAGEFRIGHT_FOUNDATION_FLAGGED_H_ 19fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 20fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar#include <media/stagefright/foundation/TypeTraits.h> 21fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 22fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnarnamespace android { 23fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 24fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar/** 25fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Flagged<T, Flag> is basically a specialized std::pair<Flag, T> that automatically optimizes out 26fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * the flag if the wrapped type T is already flagged and we can combine the outer and inner flags. 27fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 28fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Flags can be queried/manipulated via flags() an setFlags(Flags). The wrapped value can be 29fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * accessed via get(). This template is meant to be inherited by other utility/wrapper classes 30fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * that need to store integral information along with the value. 31fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 32fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Users must specify the used bits (MASK) in the flags. Flag getters and setters will enforce this 33fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * mask. _Flagged_helper::minMask<Flag> is provided to easily calculate a mask for a max value. 34fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 35fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * E.g. adding a safe flag can be achieved like this: 36fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 37fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 38fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * enum SafeFlags : uint32_t { 39fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * kUnsafe, 40fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * kSafe, 41fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * kSafeMask = _Flagged_helper::minMask(kSafe), 42fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * }; 43fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * typedef Flagged<int32_t, SafeFlags, kSafeMask> safeInt32; 44fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 45fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * safeInt32 a; 46fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * a.setFlags(kSafe); 47fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * a.get() = 15; 48fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * EXPECT_EQ(a.flags(), kSafe); 49fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * EXPECT_EQ(a.get(), 15); 50fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 51fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 52fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Flagged also supports lazy or calculated wrapping of already flagged types. Lazy wrapping is 53fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * provided automatically (flags are automatically shared if possible, e.g. mask is shifted 54fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * automatically to not overlap with used bits of the wrapped type's flags, and fall back to 55fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * unshared version of the template.): 56fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 57fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * enum OriginFlags : uint32_t { 58fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * kUnknown, 59fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * kConst, 60fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * kCalculated, 61fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * kComponent, 62fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * kApplication, 63fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * kFile, 64fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * kBinder, 65fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * kOriginMask = _Flagged_helper::minMask(kBinder), 66fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * }; 67fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * typedef Flagged<safeInt32, OriginFlags, kOriginMask> 68fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * trackedSafeInt32; 69fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 70fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * static_assert(sizeof(trackedSafeInt32) == sizeof(safeInt32), ""); 71fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 72fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * trackedSafeInt32 b(kConst, kSafe, 1); 73fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * EXPECT_EQ(b.flags(), kConst); 74fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * EXPECT_EQ(b.get().flags(), kSafe); 75fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * EXPECT_EQ(b.get().get(), 1); 76fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * b.setFlags(kCalculated); 77fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * b.get().setFlags(overflow ? kUnsafe : kSafe); 78fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 79fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * One can also choose to share some flag-bits with the wrapped class: 80fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 81fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * enum ValidatedFlags : uint32_t { 82fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * kUnsafeV = kUnsafe, 83fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * kSafeV = kSafe, 84fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * kValidated = kSafe | 2, 85fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * kSharedMaskV = kSafeMask, 86fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * kValidatedMask = _Flagged_helper::minMask(kValidated), 87fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * }; 88fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * typedef Flagged<safeInt32, ValidatedFlags, kValidatedMask, kSharedMaskV> validatedInt32; 89fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 90fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * validatedInt32 v(kUnsafeV, kSafe, 10); 91fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * EXPECT_EQ(v.flags(), kUnsafeV); 92fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * EXPECT_EQ(v.get().flags(), kUnsafe); // !kUnsafeV overrides kSafe 93fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * EXPECT_EQ(v.get().get(), 10); 94fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * v.setFlags(kValidated); 95fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * EXPECT_EQ(v.flags(), kValidated); 96fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * EXPECT_EQ(v.get().flags(), kSafe); 97fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * v.get().setFlags(kUnsafe); 98fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * EXPECT_EQ(v.flags(), 2); // NOTE: sharing masks with enums allows strange situations to occur 99fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar */ 100fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 101fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar/** 102fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Helper class for Flagged support. Encapsulates common utilities used by all 103fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * templated classes. 104fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar */ 105fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnarstruct _Flagged_helper { 106fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /** 107fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Calculates the value with a given number of top-most bits set. 108fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 109fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * This method may be called with a signed flag. 110fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 111fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param num number of bits to set. This must be between 0 and the number of bits in Flag. 112fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 113fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \return the value where only the given number of top-most bits are set. 114fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar */ 115fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar template<typename Flag> 116fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static constexpr Flag topBits(int num) { 117fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar return Flag(num > 0 ? 118fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar ~((Flag(1) << (sizeof(Flag) * 8 - is_signed_integral<Flag>::value - num)) - 1) : 119fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 0); 120fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar } 121fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 122fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /** 123fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Calculates the minimum mask required to cover a value. Used with the maximum enum value for 124fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * an unsigned flag. 125fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 126fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param maxValue maximum value to cover 127fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param shift DO NO USE. used internally 128fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 129fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \return mask that can be used that covers the maximum value. 130fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar */ 131fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar template<typename Flag> 132fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static constexpr Flag minMask(Flag maxValue, int shift=sizeof(Flag) * 4) { 133fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static_assert(is_unsigned_integral<Flag>::value, 134fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar "this method only makes sense for unsigned flags"); 135fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar return shift ? minMask<Flag>(Flag(maxValue | (maxValue >> shift)), shift >> 1) : maxValue; 136fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar } 137fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 138fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /** 139fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Returns a value left-shifted by an argument as a potential constexpr. 140fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 141fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * This method helps around the C-language limitation, when left-shift of a negative value with 142fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * even 0 cannot be a constexpr. 143fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 144fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param value value to shift 145fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param shift amount of shift 146fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \returns the shifted value as an integral type 147fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar */ 148fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar template<typename Flag, typename IntFlag = typename underlying_integral_type<Flag>::type> 149fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static constexpr IntFlag lshift(Flag value, int shift) { 150fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar return shift ? value << shift : value; 151fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar } 152fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 153fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnarprivate: 154fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 155fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /** 156fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Determines whether mask can be combined with base-mask for a given left shift. 157fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 158fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param mask desired mask 159fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param baseMask mask used by T or 0 if T is not flagged by Flag 160fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param sharedMask desired shared mask (if this is non-0, this must be mask & baseMask) 161fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param shift desired left shift to be used for mask 162fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param baseShift left shift used by T or 0 if T is not flagged by Flag 163fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param effectiveMask effective mask used by T or 0 if T is not flagged by Flag 164fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 165fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \return bool whether mask can be combined with baseMask using the desired values. 166fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar */ 167fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar template<typename Flag, typename IntFlag=typename underlying_integral_type<Flag>::type> 168fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static constexpr bool canCombine( 169fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar Flag mask, IntFlag baseMask, Flag sharedMask, int shift, 170fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar int baseShift, IntFlag effectiveMask) { 171fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar return 172fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar // verify that shift is valid and mask can be shifted 173fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar shift >= 0 && (mask & topBits<Flag>(shift)) == 0 && 174fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 175fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar // verify that base mask is part of effective mask (sanity check on arguments) 176fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar (baseMask & ~(effectiveMask >> baseShift)) == 0 && 177fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 178fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar // if sharing masks, shift must be the base's shift. 179fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar // verify that shared mask is the overlap of base mask and mask 180fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar (sharedMask ? 181fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar ((sharedMask ^ (baseMask & mask)) == 0 && 182fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar shift == baseShift) : 183fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 184fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 185fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar // otherwise, verify that there is no overlap between mask and base's effective mask 186fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar (mask & (effectiveMask >> shift)) == 0); 187fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar } 188fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 189fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 190fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /** 191fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Calculates the minimum (left) shift required to combine a mask with the mask of an 192fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * underlying type (T, also flagged by Flag). 193fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 194fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param mask desired mask 195fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param baseMask mask used by T or 0 if T is not flagged by Flag 196fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param sharedMask desired shared mask (if this is non-0, this must be mask & baseMask) 197fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param baseShift left shift used by T 198fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param effectiveMask effective mask used by T 199fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 200fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \return a non-negative minimum left shift value if mask can be combined with baseMask, 201fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * or -1 if the masks cannot be combined. -2 if the input is invalid. 202fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar */ 203fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar template<typename Flag, 204fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar typename IntFlag = typename underlying_integral_type<Flag>::type> 205fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static constexpr int getShift( 206fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar Flag mask, IntFlag baseMask, Flag sharedMask, int baseShift, IntFlag effectiveMask) { 207fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar return 208fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar // baseMask must be part of the effective mask 209fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar (baseMask & ~(effectiveMask >> baseShift)) ? -2 : 210fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 211fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar // if sharing masks, shift must be base's shift. verify that shared mask is part of 212fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar // base mask and mask, and that desired mask still fits with base's shift value 213fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar sharedMask ? 214fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar (canCombine(mask, baseMask, sharedMask, baseShift /* shift */, 215fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar baseShift, effectiveMask) ? baseShift : -1) : 216fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 217fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar // otherwise, see if 0-shift works 218fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar ((mask & effectiveMask) == 0) ? 0 : 219fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 220fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar // otherwise, verify that mask can be shifted up 221fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar ((mask & topBits<Flag>(1)) || (mask < 0)) ? -1 : 222fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 223fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar incShift(getShift(Flag(mask << 1), baseMask /* unused */, sharedMask /* 0 */, 224fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar baseShift /* unused */, effectiveMask)); 225fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar } 226fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 227fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /** 228fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Helper method that increments a non-negative (shift) value. 229fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 230fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * This method is used to make it easier to create a constexpr for getShift. 231fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 232fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param shift (shift) value to increment 233fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 234fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \return original shift if it was negative; otherwise, the shift incremented by one. 235fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar */ 236fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static constexpr int incShift(int shift) { 237fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar return shift + (shift >= 0); 238fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar } 239fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 240fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar#ifdef FRIEND_TEST 241fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar FRIEND_TEST(FlaggedTest, _Flagged_helper_Test); 242fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar#endif 243fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 244fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnarpublic: 245fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /** 246fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Base class for all Flagged<T, Flag> classes. 247fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 248fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \note flagged types do not have a member variable for the mask used by the type. As such, 249fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * they should be be cast to this base class. 250fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 251fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \todo can we replace this base class check with a static member check to remove possibility 252fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * of cast? 253fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar */ 254fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar template<typename Flag> 255fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar struct base {}; 256fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 257fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /** 258fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Type support utility that retrieves the mask of a class (T) if it is a type flagged by 259fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Flag (e.g. Flagged<T, Flag>). 260fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 261fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \note This retrieves 0 if T is a flagged class, that is not flagged by Flag or an equivalent 262fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * underlying type. 263fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 264fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Generic implementation for a non-flagged class. 265fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar */ 266fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar template< 267fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar typename T, typename Flag, 268fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar bool=std::is_base_of<base<typename underlying_integral_type<Flag>::type>, T>::value> 269fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar struct mask_of { 270fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar using IntFlag = typename underlying_integral_type<Flag>::type; 271fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static constexpr IntFlag value = Flag(0); ///< mask of a potentially flagged class 272fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static constexpr int shift = 0; ///<left shift of flags in a potentially flagged class 273fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static constexpr IntFlag effective_value = IntFlag(0); ///<effective mask of flagged class 274fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar }; 275fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 276fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /** 277fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Type support utility that calculates the minimum (left) shift required to combine a mask 278fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * with the mask of an underlying type T also flagged by Flag. 279fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 280fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \note if T is not flagged, not flagged by Flag, or the masks cannot be combined due to 281fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * incorrect sharing or the flags not having enough bits, the minimum is -1. 282fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 283fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param MASK desired mask 284fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param SHARED_MASK desired shared mask (if this is non-0, T must be an type flagged by 285fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Flag with a mask that has exactly these bits common with MASK) 286fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar */ 287fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar template<typename T, typename Flag, Flag MASK, Flag SHARED_MASK> 288fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar struct min_shift { 289fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /// minimum (left) shift required, or -1 if masks cannot be combined 290fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static constexpr int value = 291fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar getShift(MASK, mask_of<T, Flag>::value, SHARED_MASK, 292fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar mask_of<T, Flag>::shift, mask_of<T, Flag>::effective_value); 293fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar }; 294fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 295fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /** 296fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Type support utility that calculates whether the flags of T can be combined with MASK. 297fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 298fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param MASK desired mask 299fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param SHARED_MASK desired shared mask (if this is non-0, T MUST be an type flagged by 300fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Flag with a mask that has exactly these bits common with MASK) 301fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar */ 302fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar template< 303fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar typename T, typename Flag, Flag MASK, 304fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar Flag SHARED_MASK=Flag(0), 305fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar int SHIFT=min_shift<T, Flag, MASK, SHARED_MASK>::value> 306fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar struct can_combine { 307fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar using IntFlag = typename underlying_integral_type<Flag>::type; 308fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /// true if this mask can be combined with T's existing flag. false otherwise. 309fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static constexpr bool value = 310fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar std::is_base_of<base<IntFlag>, T>::value 311fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar && canCombine(MASK, mask_of<T, Flag>::value, SHARED_MASK, SHIFT, 312fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar mask_of<T, Flag>::shift, mask_of<T, Flag>::effective_value); 313fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar }; 314fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar}; 315fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 316fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar/** 317fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Template specialization for the case when T is flagged by Flag or a compatible type. 318fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar */ 319fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnartemplate<typename T, typename Flag> 320fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnarstruct _Flagged_helper::mask_of<T, Flag, true> { 321fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar using IntType = typename underlying_integral_type<Flag>::type; 322fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static constexpr IntType value = T::sFlagMask; 323fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static constexpr int shift = T::sFlagShift; 324fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static constexpr IntType effective_value = T::sEffectiveMask; 325fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar}; 326fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 327fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar/** 328fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Main Flagged template that adds flags to an object of another type (in essence, creates a pair) 329fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 330fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Flag must be an integral type (enums are allowed). 331fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 332fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \note We could make SHARED_MASK be a boolean as it must be either 0 or MASK & base's mask, but we 333fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * want it to be spelled out for safety. 334fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 335fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param T type of object wrapped 336fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param Flag type of flag 337fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param MASK mask for the bits used in flag (before any shift) 338fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param SHARED_MASK optional mask to be shared with T (if this is not zero, SHIFT must be 0, and 339fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * it must equal to MASK & T's mask) 340fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param SHIFT optional left shift for MASK to combine with T's mask (or -1, if masks should not 341fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * be combined.) 342fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar */ 343fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnartemplate< 344fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar typename T, typename Flag, Flag MASK, Flag SHARED_MASK=(Flag)0, 345fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar int SHIFT=_Flagged_helper::min_shift<T, Flag, MASK, SHARED_MASK>::value, 346fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar typename IntFlag=typename underlying_integral_type<Flag>::type, 347fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar bool=_Flagged_helper::can_combine<T, IntFlag, MASK, SHARED_MASK, SHIFT>::value> 348fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnarclass Flagged : public _Flagged_helper::base<IntFlag> { 349fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static_assert(SHARED_MASK == 0, 350fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar "shared mask can only be used with common flag types " 351fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar "and must be part of mask and mask of base type"); 352fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static_assert((_Flagged_helper::topBits<Flag>(SHIFT) & MASK) == 0, "SHIFT overflows MASK"); 353fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 354fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static constexpr Flag sFlagMask = MASK; ///< the mask 355fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static constexpr int sFlagShift = SHIFT > 0 ? SHIFT : 0; ///< the left shift applied to flags 356fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 357fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar friend struct _Flagged_helper; 358fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar#ifdef FRIEND_TEST 359fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static constexpr bool sFlagCombined = false; 360fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar FRIEND_TEST(FlaggedTest, _Flagged_helper_Test); 361fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar#endif 362fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 363fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar T mValue; ///< wrapped value 364fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar IntFlag mFlags; ///< flags 365fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 366fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnarprotected: 367fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /// The effective combined mask used by this class and any wrapped classes if the flags are 368fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /// combined. 369fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static constexpr IntFlag sEffectiveMask = _Flagged_helper::lshift(MASK, sFlagShift); 370fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 371fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /** 372fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Helper method used by subsequent flagged wrappers to query flags. Returns the 373fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * flags for a particular mask and left shift. 374fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 375fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param mask bitmask to use 376fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param shift left shifts to use 377fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 378fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \return the requested flags 379fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar */ 380fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar inline constexpr IntFlag getFlagsHelper(IntFlag mask, int shift) const { 381fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar return (mFlags >> shift) & mask; 382fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar } 383fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 384fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /** 385fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Helper method used by subsequent flagged wrappers to apply combined flags. Sets the flags 386fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * in the bitmask using a particulare left shift. 387fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 388fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param mask bitmask to use 389fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param shift left shifts to use 390fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param flags flags to update (any flags within the bitmask are updated to their value in this 391fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * argument) 392fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar */ 393fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar inline void setFlagsHelper(IntFlag mask, int shift, IntFlag flags) { 394fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar mFlags = Flag((mFlags & ~(mask << shift)) | ((flags & mask) << shift)); 395fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar } 396fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 397fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnarpublic: 398fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /** 399fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Wrapper around base class constructor. These take the flags as their first 400fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * argument and pass the rest of the arguments to the base class constructor. 401fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 402fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param flags initial flags 403fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar */ 404fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar template<typename ...Args> 405fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar constexpr Flagged(Flag flags, Args... args) 406fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar : mValue(std::forward<Args>(args)...), 407fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar mFlags(Flag(_Flagged_helper::lshift(flags & sFlagMask, sFlagShift))) { } 408fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 409fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /** Gets the wrapped value as const. */ 410fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar inline constexpr const T &get() const { return mValue; } 411fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 412fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /** Gets the wrapped value. */ 413fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar inline T &get() { return mValue; } 414fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 415fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /** Gets the flags. */ 416fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar constexpr Flag flags() const { 417fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar return Flag(getFlagsHelper(sFlagMask, sFlagShift)); 418fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar } 419fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 420fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /** Sets the flags. */ 421fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar void setFlags(Flag flags) { 422fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar setFlagsHelper(sFlagMask, sFlagShift, flags); 423fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar } 424fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar}; 425fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 426fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar/* 427fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * TRICKY: we cannot implement the specialization as: 428fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 429fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * class Flagged : base<Flag> { 430fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * T value; 431fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * }; 432fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 433fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Because T also inherits from base<Flag> and this runs into a compiler bug where 434fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * sizeof(Flagged) > sizeof(T). 435fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 436fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Instead, we must inherit directly from the wrapped class 437fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 438fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar */ 439fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar#if 0 440fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnartemplate< 441fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar typename T, typename Flag, Flag MASK, Flag SHARED_MASK, int SHIFT> 442fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnarclass Flagged<T, Flag, MASK, SHARED_MASK, SHIFT, true> : public _Flagged_helper::base<Flag> { 443fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnarprivate: 444fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar T mValue; 445fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar}; 446fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar#else 447fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar/** 448fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Specialization for the case when T is derived from Flagged<U, Flag> and flags can be combined. 449fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar */ 450fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnartemplate< 451fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar typename T, typename Flag, Flag MASK, Flag SHARED_MASK, int SHIFT, typename IntFlag> 452fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnarclass Flagged<T, Flag, MASK, SHARED_MASK, SHIFT, IntFlag, true> : private T { 453fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static_assert(is_integral_or_enum<Flag>::value, "flag must be integer or enum"); 454fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 455fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static_assert(SHARED_MASK == 0 || SHIFT == 0, "cannot overlap masks when using SHIFT"); 456fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static_assert((SHARED_MASK & ~MASK) == 0, "shared mask must be part of the mask"); 457fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static_assert((SHARED_MASK & ~T::sEffectiveMask) == 0, 458fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar "shared mask must be part of the base mask"); 459fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static_assert(SHARED_MASK == 0 || (~SHARED_MASK & (MASK & T::sEffectiveMask)) == 0, 460fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar "mask and base mask can only overlap in shared mask"); 461fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 462fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static constexpr Flag sFlagMask = MASK; ///< the mask 463fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static constexpr int sFlagShift = SHIFT; ///< the left shift applied to the flags 464fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 465fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar#ifdef FRIEND_TEST 466fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar const static bool sFlagCombined = true; 467fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar FRIEND_TEST(FlaggedTest, _Flagged_helper_Test); 468fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar#endif 469fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 470fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnarprotected: 471fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /// The effective combined mask used by this class and any wrapped classes if the flags are 472fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /// combined. 473fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar static constexpr IntFlag sEffectiveMask = Flag((MASK << SHIFT) | T::sEffectiveMask); 474fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar friend struct _Flagged_helper; 475fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 476fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnarpublic: 477fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /** 478fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * Wrapper around base class constructor. These take the flags as their first 479fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * argument and pass the rest of the arguments to the base class constructor. 480fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * 481fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar * \param flags initial flags 482fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar */ 483fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar template<typename ...Args> 484fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar constexpr Flagged(Flag flags, Args... args) 485fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar : T(std::forward<Args>(args)...) { 486fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar // we construct the base class first and apply the flags afterwards as 487fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar // base class may not have a constructor that takes flags even if it is derived from 488fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar // Flagged<U, Flag> 489fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar setFlags(flags); 490fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar } 491fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 492fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /** Gets the wrapped value as const. */ 493fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar inline constexpr T &get() const { return *this; } 494fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 495fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /** Gets the wrapped value. */ 496fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar inline T &get() { return *this; } 497fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 498fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /** Gets the flags. */ 499fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar Flag constexpr flags() const { 500fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar return Flag(this->getFlagsHelper(sFlagMask, sFlagShift)); 501fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar } 502fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 503fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar /** Sets the flags. */ 504fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar void setFlags(Flag flags) { 505fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar this->setFlagsHelper(sFlagMask, sFlagShift, flags); 506fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar } 507fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar}; 508fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar#endif 509fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 510fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar} // namespace android 511fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 512fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar#endif // STAGEFRIGHT_FOUNDATION_FLAGGED_H_ 513fba972f9d7f87c47ac0820b7f99420acc7e5dc36Lajos Molnar 514