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