1/*
2 * Copyright 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "Flagged_test"
19
20#include <gtest/gtest.h>
21
22#include <media/stagefright/foundation/Flagged.h>
23
24namespace android {
25
26/**
27 * Helper template that can be used to print values in static_assert error messages.
28 *
29 * Use integers here.
30 */
31template<bool, int ...N>
32struct _print_as_warning { };
33
34template<int ...N>
35struct _print_as_warning<true, N...> : std::true_type { };
36
37#define static_assert_equals(a, b, msg) \
38static_assert(_print_as_warning<(a) == (b), a, b>::value, msg)
39
40class FlaggedTest : public ::testing::Test {
41protected:
42    // empty structs
43    struct A0 { };
44    struct A1 { };
45    struct A_A0 : public A0 { };
46
47    // simple struct
48    struct BB {
49        int32_t i;
50        uint32_t u;
51    };
52
53    // struct inheriting from A0
54    struct BB_A0 : public A0 {
55        int32_t i;
56        uint32_t u;
57    };
58
59    // struct inheriting from struct inheriting A0
60    struct BB_AA0 : public A_A0 {
61        int32_t i;
62        uint32_t u;
63    };
64
65    // struct that wraps
66    struct WBBA0 {
67        BB_A0 b;
68    };
69
70    struct WBBA0_A1 : public A1 {
71        BB_A0 b;
72    };
73
74    struct WBBA0_A0 : public A0 {
75        BB_A0 b;
76    };
77
78    struct WBB_A0 : public A0 {
79        BB b;
80    };
81
82    struct WBBA0_AA0 : public A_A0 {
83        BB_A0 b;
84    };
85
86    struct WBBAA0_A0 : public A0 {
87        BB_AA0 b;
88    };
89
90    struct WWBBA0_A0 : public A0 {
91        WBBA0 b;
92    };
93};
94
95/**
96 * This test is here to confirm the handling of wrapping classes that inherit from an interface
97 * while also inheriting from that same interface. While we no longer use this construct, we want
98 * to track if this defect is ever fixed.
99 */
100TEST_F(FlaggedTest, StaticSanityTests) {
101    static_assert(sizeof(A0) == 1, "");
102    static_assert(sizeof(A1) == 1, "");
103    static_assert(sizeof(A_A0) == 1, "");
104
105    static constexpr size_t size = sizeof(BB); // original [pair]
106
107    // inheriting from A0 does not increase size
108    static_assert(sizeof(BB_A0) == size, ""); // [pair]:A0
109    static_assert(sizeof(BB_AA0) == size, ""); // [pair]:[:A0]
110
111     // wrapping a class that inherits from A0 does not increase size
112    static_assert(sizeof(WBBA0) == size, ""); // [ [pair]:[:A0] ]
113
114    // wrapping a class that inherits from A0 while also inheriting from A1 does not increase size
115    static_assert(sizeof(WBBA0_A1) == size, ""); // [ [pair]:A0 ]:A1
116
117    // wrapping a class that inherits from A0 while also inheriting from A0 DOES increase size
118    EXPECT_GT(sizeof(WBBA0_A0), size); // [ [pair]:A0 ]:A0
119
120    // wrapping a class that does not inherit from A0 while inheriting from A0 does not increase
121    // size
122    static_assert(sizeof(WBB_A0) == size, ""); // [[pair]]:A0
123
124    // wrapping a class that inherits from A0 while also inheriting from a class that inherits
125    // from A0 does increase size
126    EXPECT_GT(sizeof(WBBA0_AA0), size); // [ [pair]:A0 ]:[:A0]
127
128    // wrapping a class that indirectly inherits from A0 while also inheriting from A0 does
129    // increase size
130    EXPECT_GT(sizeof(WBBAA0_A0), size); // [ [pair]:[:A0] ]:A0
131
132    // wrapping a class that inherits from A0 while also inheriting A0 does increase size
133    EXPECT_GT(sizeof(WWBBA0_A0), size); //  [ [pair]:A0 ]:A0
134}
135
136enum FLAG : int32_t {
137    kMask0 = 0x0FF,
138    kFlag0_A = 0x0AA,
139    kFlag0_B = 0x0BB,
140    kFlag0_C = 0x0CC,
141    kMask1 = 0xFF0,
142    kFlag1_A = 0xAA0,
143    kFlag1_B = 0xBB0,
144    kFlag1_C = 0xCC0,
145    kMaskCommon = 0x0F0,
146};
147
148TEST_F(FlaggedTest, BasicExample) {
149    enum SafeFlags : uint32_t {
150      kUnsafe,
151      kSafe,
152      kSafeMask = _Flagged_helper::minMask(kSafe),
153    };
154    typedef Flagged<int32_t, SafeFlags, kSafeMask> safeInt32;
155
156    safeInt32 a(kUnsafe);
157    a.setFlags(kSafe);
158    a.get() = 15;
159    EXPECT_EQ(a.flags(), kSafe);
160    EXPECT_EQ(a.get(), 15);
161
162    enum OriginFlags : uint32_t {
163      kUnknown,
164      kConst,
165      kCalculated,
166      kComponent,
167      kApplication,
168      kFile,
169      kBinder,
170      kOriginMask = _Flagged_helper::minMask(kBinder),
171    };
172    typedef Flagged<safeInt32, OriginFlags, kOriginMask>
173             trackedSafeInt32;
174
175    static_assert(sizeof(trackedSafeInt32) == sizeof(safeInt32), "");
176
177    trackedSafeInt32 b(kConst, kSafe, 1);
178    EXPECT_EQ(b.flags(), kConst);
179    EXPECT_EQ(b.get().flags(), kSafe);
180    EXPECT_EQ(b.get().get(), 1);
181    b.setFlags(kCalculated);
182    volatile bool overflow = true;
183    b.get().setFlags(overflow ? kUnsafe : kSafe);
184
185    enum ValidatedFlags : uint32_t {
186      kUnsafeV = kUnsafe,
187      kSafeV = kSafe,
188      kValidated = kSafe | 2,
189      kSharedMaskV = kSafeMask,
190      kValidatedMask = _Flagged_helper::minMask(kValidated),
191    };
192    typedef Flagged<safeInt32, ValidatedFlags, kValidatedMask, kSharedMaskV> validatedInt32;
193
194    validatedInt32 v(kUnsafeV, kSafe, 10);
195    EXPECT_EQ(v.flags(), kUnsafeV);
196    EXPECT_EQ(v.get().flags(), kUnsafe);  // !kUnsafeV overrides kSafe
197    EXPECT_EQ(v.get().get(), 10);
198    v.setFlags(kValidated);
199    EXPECT_EQ(v.flags(), kValidated);
200    EXPECT_EQ(v.get().flags(), kSafe);
201    v.get().setFlags(kUnsafe);
202    EXPECT_EQ(v.flags(), 2);  // NOTE: sharing masks with enums allows strange situations to occur
203}
204
205TEST_F(FlaggedTest, _Flagged_helper_Test) {
206    using helper = _Flagged_helper;
207
208    using i32 = int32_t;
209    using u32 = uint32_t;
210    using u8 = uint8_t;
211
212    // base2
213    static_assert(Flagged<i32, u32, 0u, 0u, 0>::sFlagMask == 0u, "");
214    static_assert(Flagged<i32, u32, 0u, 0u, 0>::sFlagShift == 0, "");
215    static_assert(Flagged<i32, u32, 0u, 0u, 0>::sEffectiveMask == 0u, "");
216
217    static_assert(Flagged<i32, u32, 0u, 0u, 10>::sFlagMask == 0u, "");
218    static_assert(Flagged<i32, u32, 0u, 0u, 10>::sFlagShift == 10, "");
219    static_assert(Flagged<i32, u32, 0u, 0u, 10>::sEffectiveMask == 0u, "");
220
221    static_assert(Flagged<i32, u32, 0u, 0u, -1>::sFlagMask == 0u, "");
222    static_assert(Flagged<i32, u32, 0u, 0u, -1>::sFlagShift == 0, "");
223    static_assert(Flagged<i32, u32, 0u, 0u, -1>::sEffectiveMask == 0u, "");
224
225    static_assert(Flagged<i32, u32, 99u, 0u, 0>::sFlagMask == 99u, "");
226    static_assert(Flagged<i32, u32, 99u, 0u, 0>::sFlagShift == 0, "");
227    static_assert(Flagged<i32, u32, 99u, 0u, 0>::sEffectiveMask == 99u, "");
228
229    static_assert(Flagged<i32, u32, 0x99u, 0u, 12>::sFlagMask == 0x99u, "");
230    static_assert(Flagged<i32, u32, 0x99u, 0u, 12>::sFlagShift == 12, "");
231    static_assert(Flagged<i32, u32, 0x99u, 0u, 12>::sEffectiveMask == 0x99000u, "");
232
233    static_assert(Flagged<i32, u32, 99u, 0u, -1>::sFlagMask == 99u, "");
234    static_assert(Flagged<i32, u32, 99u, 0u, -1>::sFlagShift == 0, "");
235    static_assert(Flagged<i32, u32, 99u, 0u, -1>::sEffectiveMask == 99u, "");
236
237    // mask_of<T, Flag>
238    // also Flagged<> no default
239    typedef Flagged<i32, u32, 0x800F /* mask */, 0 /* shared mask */, 0 /* shift */> i32_800f_0;
240    typedef Flagged<i32, u32, 0x800F /* mask */, 0 /* shared mask */, 4 /* shift */> i32_800f_4;
241    // this also tests that these types can be instantiated
242    static_assert(sizeof(i32_800f_0) >= sizeof(i32) + sizeof(u32),
243                  "should be at least size of component types");
244    static_assert(sizeof(i32_800f_4) == sizeof(i32_800f_0), "regardless of shift");
245    static_assert(!i32_800f_0::sFlagCombined, "");
246    static_assert(!i32_800f_4::sFlagCombined, "");
247
248    static_assert(helper::mask_of<i32_800f_0, u32>::value == 0x800F, "incorrect mask");
249    static_assert(helper::mask_of<i32_800f_0, i32>::value == 0,
250                  "mask should be 0 when types mismatch");
251    static_assert(helper::mask_of<i32_800f_0, u32>::effective_value == 0x800F, "incorrect mask");
252    static_assert(helper::mask_of<i32_800f_0, i32>::effective_value == 0,
253                  "mask should be 0 when types mismatch");
254    static_assert(helper::mask_of<i32_800f_0, u32>::shift == 0, "incorrect shift");
255    static_assert(helper::mask_of<i32_800f_0, i32>::shift == 0,
256                  "shift should be 0 when types mismatch");
257
258    static_assert(helper::mask_of<i32_800f_4, u32>::value == 0x800F, "incorrect mask");
259    static_assert(helper::mask_of<i32_800f_4, i32>::value == 0,
260                  "mask should be 0 when types mismatch");
261    static_assert(helper::mask_of<i32_800f_4, u32>::effective_value == 0x800F0, "incorrect mask");
262    static_assert(helper::mask_of<i32_800f_4, i32>::effective_value == 0,
263                  "mask should be 0 when types mismatch");
264    static_assert(helper::mask_of<i32_800f_4, u32>::shift == 4, "incorrect shift");
265    static_assert(helper::mask_of<i32_800f_4, i32>::shift == 0,
266                  "shift should be 0 when types mismatch");
267    static_assert(helper::mask_of<i32, u32>::value == 0, "mask should be 0 if not masked");
268    static_assert(helper::mask_of<i32, i32>::value == 0, "mask should be 0 if not masked");
269
270    // lshift(value, n)
271    static_assert(helper::lshift(0U, 0) == 0U, "");
272    static_assert(helper::lshift(0U, 30) == 0U, "");
273    static_assert(helper::lshift(1U, 0) == 1U, "");
274    static_assert(helper::lshift(1U, 10) == 1024U, "");
275    static_assert(helper::lshift(10U, 10) == 10240U, "");
276    static_assert(helper::lshift(10, 10) == 10240, "");
277    static_assert(helper::lshift(-10, 0) == -10, "");
278    // static_assert(helper::lshift(-10, 10) == -10240, ""); // error: left shift of negative value
279
280    // minMask(maxValue)
281    static_assert(helper::minMask(0U) == 0U, "lowest 0 bits");
282    static_assert(helper::minMask(1U) == 1U, "lowest 1 bit");
283    static_assert(helper::minMask(2U) == 3U, "lowest 2 bits");
284    static_assert(helper::minMask(3U) == 3U, "lowest 2 bits");
285    static_assert(helper::minMask(4U) == 7U, "lowest 3 bits");
286    static_assert(helper::minMask(~0U) == ~0U, "all bits");
287    // static_assert(helper::minMask(10) == 0xF, "all bits"); // error: must be unsigned
288
289    // topBits(n)
290    static_assert(helper::topBits<u32>(0) == 0U, "top 0 bit");
291    static_assert(helper::topBits<u32>(1) == 0x80000000U, "top 1 bit");
292    static_assert(helper::topBits<u32>(2) == 0xC0000000U, "top 2 bits");
293    static_assert(helper::topBits<u32>(12) == 0xFFF00000U, "top 12 bits");
294    static_assert(helper::topBits<u32>(32) == 0xFFFFFFFFU, "all bits");
295    // static_assert(helper::topBits<u32>(33) == 0xFFFFFFFFU, ""); // should OVERFLOW
296
297    static_assert(helper::topBits<u8>(0) == 0U, "top 0 bit");
298    static_assert(helper::topBits<u8>(1) == 0x80U, "top 1 bit");
299    static_assert(helper::topBits<u8>(2) == 0xC0U, "top 2 bit");
300    static_assert(helper::topBits<u8>(8) == 0xFFU, "all bits");
301    // static_assert(helper::topBits<u8>(9) == 0xFFU, ""); // should OVERFLOW
302
303    // getShift(mask, base, shared, base-shift, base-effective)
304    static_assert(helper::getShift(0u, 0u, 0u, 0, 0u) == 0, "no flag require no shift");
305    static_assert(helper::getShift(0u, 0u, 1u, 0, 0u) == -1,
306                  "shared must be within mask and base mask");
307    static_assert(helper::getShift(0u, 1u, 1u, 0, 1u) == -1, "shared must be within mask");
308    static_assert(helper::getShift(0u, 1u, 0u, 0, 1u) == 0,
309                  "no flags require no shift even with base mask");
310    static_assert(helper::getShift(0u, 1u, 0u, 1, 2u) == 0,
311                  "no flags require no shift even with shifted base mask");
312    static_assert(helper::getShift(1u, 0u, 0u, 0, 0u) == 0, "no base mask requires no shift");
313    static_assert(helper::getShift(1u, 1u, 0u, 0, 1u) == 1,
314                  "overlapping mask and basemask requires shift");
315    static_assert(helper::getShift(1u, 1u, 0u, 0, 1u) == 1,
316                  "overlapping mask and basemask requires shift");
317    static_assert(helper::getShift(1u, 1u, 1u, 0, 1u) == 0,
318                  "shared mask requires using base shift");
319    static_assert(helper::getShift(1u, 1u, 1u, 1, 2u) == 1,
320                  "shared mask requires using base shift");
321    static_assert(helper::getShift(3u, 5u, 1u, 0, 5u) == 0,
322                  "mask and basemask that overlap only in shared region requires no shift");
323    static_assert(helper::getShift(3u, 7u, 1u, 0, 7u) == -1,
324                  "mask and basemask must not overlap in more than shared region");
325    static_assert(helper::getShift(1u, 0u, 1u, 0, 0u) == -1, "shared must be within base mask");
326
327    static_assert(helper::getShift(0u, 1u, 0u, 1, 1u) == -2, "effective mask must cover base mask");
328    static_assert(helper::getShift(0u, 5u, 0u, 1, 2u) == -2, "effective mask must cover base mask");
329    static_assert(helper::getShift(0u, 5u, 0u, 1, 10u) == 0, "");
330    static_assert(helper::getShift(0u, 5u, 0u, 1, 31u) == 0,
331                  "effective mask can be larger than base mask");
332
333    static_assert(helper::getShift(0x800Fu, 0x800Fu, 0x800Fu, 0, 0x800Fu) == 0,
334                  "(0x800F << 0) & 0x800F == 0x800F");
335    static_assert(helper::getShift(0x800Fu, 0x800Fu, 0x800Fu, 16, 0x800F0000u) == 16,
336                  "(0x800F << 0) & 0x800F == 0x800F");
337    static_assert(helper::getShift(0x1800Fu, 0x800Fu, 0x800Fu, 0, 0x800Fu) == 0,
338                  "(0x1800F << 0) & 0x800F == 0x800F");
339    static_assert(helper::getShift(0x1800Fu, 0x800Fu, 0x800Fu, 16, 0x800F0000u) == -1,
340                  "(0x1800F << 16) overflows");
341
342    // verify that when not sharing masks, effective mask makes the difference
343    static_assert(helper::getShift(0x800Fu, 0u, 0u, 0, 0x800Fu) == 4,
344                  "(0x800F << 4) & 0x800F == 0");
345    static_assert(helper::getShift(0x800Fu, 0x2u, 0u, 0, 0x8002u) == 2,
346                  "(0x800F << 2) & 0x8002 == 0");
347    static_assert(helper::getShift(0x800Fu, 0x1u, 0u, 15, 0x8001u) == 1,
348                  "(0x800F << 1) & 0x8001 == 0");
349    static_assert(helper::getShift(0x800Fu, 0x800Fu, 0u, 16, 0x800F0000u) == 0,
350                  "0x800F & 0x800F0000 == 0");
351    static_assert(helper::getShift(0x800Fu, 0x800F8000u, 0u, 0, 0x800F8000u) == 5,
352                  "(0x800F << 5) & 0x800F8000 == 0");
353    static_assert(helper::getShift(0x800Fu, 0xF0000u, 0u, 0, 0x800F8000u) == 5,
354                  "(0x800F << 5) & 0x800F8000 == 0");
355    static_assert(helper::getShift(0x800Fu, 0x1Fu, 0u, 15, 0x800F8000u) == 5,
356                  "(0x800F << 5) & 0x800F8000 == 0");
357    static_assert(helper::getShift(0xFFu, 0x80808080u, 0u, 0, 0x80808080u) == -1,
358                  "0xFF always overlaps with 0x80808080");
359    static_assert(helper::getShift(0xFFu, 0x10001000u, 0u, 3, 0x80808080u) == -1,
360                  "0xFF always overlaps with 0x80808080");
361    static_assert(helper::getShift(0xFFu, 0x80808040u, 0u, 0, 0x80808040u) == 7,
362                  "(0xFF << 7) & 0x 80808040 == 0");
363
364    // verify min_shift (mask must be positive or no shift can be required)
365    static_assert(helper::getShift(0xFF, 0x40808040, 0, 0, 0x40808040) == 7, "");
366    static_assert(helper::getShift((i32)0x800000FF, 0x40808040, 0, 0, 0x40808040) == -1, "");
367    static_assert(helper::getShift(0x100000FF, 0x40808040, 0, 0, 0x40808040) == -1, "");
368    static_assert(helper::getShift(0xFF, (i32)0x80808040, 0, 0, (i32)0x80808040) == 7, "");
369    static_assert(helper::getShift((i32)0x80007F80, 0x40808040, 0, 0, 0x40808040) == 0, "");
370
371    // shared mask can also be negative (but not shift can be required)
372    static_assert(helper::getShift((i32)0x80007F80, (i32)0xC0808040, (i32)0x80000000,
373                                   0, (i32)0xC0808040) == 0, "");
374    static_assert(helper::getShift((i32)0x80007F80, (i32)0xC0808040, (i32)0xC0000000,
375                                   0, (i32)0xC0808040) == -1, "");
376    static_assert(helper::getShift((i32)0x80007F80, (i32)0x60404020, (i32)0x60000000,
377                                   1, (i32)0xC0808040) == -1, "");
378
379    // min_shift
380    typedef Flagged<i32, u32, 0u> i32_0_0;
381    typedef Flagged<i32, u32, 1u> i32_1_0;
382    typedef Flagged<i32, u32, 1u, 0u, 1> i32_1_1;
383
384    // this is a wrapper over getShift, so same test cases apply when T is flagged
385    static_assert(helper::min_shift<i32_0_0, u32, 0u, 0u>::value == 0, "");
386    static_assert(helper::min_shift<i32_0_0, u32, 0u, 1u>::value == -1, "");
387    static_assert(helper::min_shift<i32_1_0, u32, 0u, 1u>::value == -1, "");
388    static_assert(helper::min_shift<i32_1_0, u32, 0u, 0u>::value == 0, "");
389    static_assert(helper::min_shift<i32_0_0, u32, 1u, 0u>::value == 0, "");
390    static_assert(helper::min_shift<i32_1_0, u32, 1u, 0u>::value == 1, "");
391    static_assert(helper::min_shift<i32_1_0, u32, 1u, 1u>::value == 0, "");
392    static_assert(helper::min_shift<i32_1_1, u32, 1u, 1u>::value == 1, "");
393    static_assert(helper::min_shift<i32_1_1, u32, 3u, 0u>::value == 2, "");
394    static_assert(helper::min_shift<Flagged<i32, u32, 5u>, u32, 3u, 1u>::value == 0, "");
395    static_assert(helper::min_shift<Flagged<i32, u32, 7u>, u32, 3u, 1u>::value == -1, "");
396    static_assert(helper::min_shift<i32_0_0, u32, 1u, 1u>::value == -1, "");
397
398    static_assert(helper::min_shift<i32_800f_0, u32, 0x800Fu, 0u>::value == 4, "");
399    static_assert(helper::min_shift<i32_800f_4, u32, 0x1800Fu, 0x800Fu>::value == 4, "");
400    static_assert(helper::min_shift<i32_800f_4, u32, 0x800Fu, 0u>::value == 0, "");
401    static_assert(helper::min_shift<Flagged<i32, u32, 0x8002u>, u32, 0x800Fu, 0u>::value == 2, "");
402    static_assert(helper::min_shift<Flagged<i32, u32, 0x8001u>, u32, 0x800Fu, 0u>::value == 1, "");
403    static_assert(
404            helper::min_shift<Flagged<i32, u32, 0x800Fu, 0u, 16>, u32, 0x800Fu, 0u>::value == 0, "");
405    static_assert(
406            helper::min_shift<Flagged<i32, u32, 0x800F8000u>, u32, 0x800Fu, 0u>::value == 5, "");
407    static_assert(
408            helper::min_shift<Flagged<i32, u32, 0x80808080u>, u32, 0xFFu, 0u>::value == -1, "");
409    static_assert(
410            helper::min_shift<Flagged<i32, u32, 0x80808040u>, u32, 0xFFu, 0u>::value == 7, "");
411
412    // for min_shift, non-tagged type behaves as if having base mask of 0
413    static_assert(helper::min_shift<i32, u32, 0u, 0u>::value == 0, "");
414    static_assert(helper::min_shift<u32, u32, 0u, 0u>::value == 0, "");
415    static_assert(helper::min_shift<i32, u32, 0u, 0u>::value == 0, "");
416    static_assert(helper::min_shift<i32, u32, 0u, 1u>::value == -1, "");
417    static_assert(helper::min_shift<i32, u32, 1u, 0u>::value == 0, "");
418    static_assert(helper::min_shift<i32, u32, 1u, 1u>::value == -1, "");
419
420    // verify min_shift (mask must be positive or no shift can be required)
421    static_assert(helper::min_shift<Flagged<i32, i32, 0x40808040>, i32, 0xFF, 0>::value == 7, "");
422    static_assert(helper::min_shift<Flagged<i32, i32, 0x40808040>,
423                                    i32, (i32)0x800000FF, 0>::value == -1, "");
424    static_assert(helper::min_shift<Flagged<i32, i32, 0x40808040>,
425                                    i32, 0x100000FF, 0>::value == -1, "");
426    static_assert(helper::min_shift<Flagged<i32, i32, (i32)0x80808040>,
427                                    i32, 0xFF, 0>::value == 7, "");
428    static_assert(helper::min_shift<Flagged<i32, i32, 0x40808040>,
429                                    i32, (i32)0x80007F80, 0>::value == 0, "");
430
431    static_assert(helper::min_shift<Flagged<i32, i32, (i32)0x80808040>,
432                                    i32, (i32)0x80007F80, (i32)0x80000000>::value == 0, "");
433    static_assert(helper::min_shift<Flagged<i32, i32, (i32)0xC0808040>,
434                                    i32, (i32)0x80007F80, (i32)0xC0000000>::value == -1, "");
435    // note: cannot create a flagged type with signed flag and shift
436    // static_assert(helper::min_shift<Flagged<i32, i32, (i32)0x60404020, 0, 1>,
437    //                                i32, (i32)0x40003FC0, (i32)0x40000000>::value == -1, "");
438
439    typedef Flagged<i32, u32, 0x800F /* mask */, 0 /* shared mask */, 16 /* shift */> i32_800f_16;
440    static_assert_equals(sizeof(i32_800f_16), sizeof(i32_800f_0), "");
441    // shifted mask overflows!
442    // typedef Flagged<i32, u32, 0x800F /* mask */, 0 /* shared mask */, 17 /* shift */> i32_800f_17;
443    // static_assert(sizeof(i32_800f_17) == sizeof(i32_800f_0), "");
444    typedef Flagged<i32, i32, 0x800F /* mask */, 0 /* shared mask */, 15 /* shift */> i32_800f_15i;
445    static_assert_equals(sizeof(i32_800f_15i), sizeof(i32_800f_0), "");
446    // shifted mask overflows!
447    // typedef Flagged<i32, i32, 0x800F /* mask */, 0 /* shared mask */, 16 /* shift */> i32_800f_16i;
448    // static_assert(sizeof(i32_800f_16i) == sizeof(i32_800f_0), "");
449
450    // canCombine(mask, base, shared, shift, base-shift, base-effective)
451    static_assert(helper::canCombine(0u, 0u, 0u, 0, 0, 0u), "using no mask is valid");
452    static_assert(helper::canCombine(0u, 0u, 0u, 0, 0, 0u), "");
453    static_assert(helper::canCombine(0u, 0u, 0u, 4, 0, 0u), "");
454    static_assert(!helper::canCombine(0u, 0u, 1u, 0, 0, 0u),
455                  "shared mask must be the overlap of masks");
456    static_assert(helper::canCombine(1u, 0u, 0u, 0, 0, 0u), "");
457    static_assert(helper::canCombine(1u, 0u, 0u, 4, 0, 0u), "");
458    static_assert(helper::canCombine(3u, 5u, 1u, 0, 0, 5u), "");
459    static_assert(!helper::canCombine(3u, 3u, 3u, 1, 0, 3u), "shift must match when sharing mask");
460    static_assert(helper::canCombine(3u, 3u, 3u, 1, 1, 6u), "");
461    static_assert(!helper::canCombine(3u, 3u, 3u, 1, 2, 12u), "shift must match when sharing mask");
462    static_assert(!helper::canCombine(3u, 7u, 1u, 0, 0, 7u), "");
463    static_assert(!helper::canCombine(1u, 0u, 1u, 0, 0, 0u), "");
464
465    static_assert(!helper::canCombine(0u, 1u, 1u, 0, 0, 1u),
466                  "shared mask must be the overlap of masks");
467    static_assert(helper::canCombine(0u, 1u, 0u, 0, 0, 1u), "");
468    static_assert(helper::canCombine(0u, 1u, 0u, 4, 0, 1u), "");
469    static_assert(helper::canCombine(1u, 1u, 0u, 1, 0, 1u), "");
470    static_assert(!helper::canCombine(1u, 1u, 0u, 0, 0, 1u), "");
471    static_assert(helper::canCombine(1u, 1u, 0u, 1, 0, 1u), "");
472    static_assert(helper::canCombine(1u, 1u, 1u, 0, 0, 1u), "");
473    static_assert(!helper::canCombine(1u, 1u, 1u, 1, 0, 1u), "shift must match when sharing mask");
474
475    static_assert(helper::canCombine(0x800Fu, 0x800Fu, 0u, 4, 0, 0x800Fu), "");
476    static_assert(!helper::canCombine(0x800Fu, 0x800Fu, 0u, 1, 0, 0x800Fu), "");
477    static_assert(helper::canCombine(0x800Fu, 0x8002u, 0u, 2, 0, 0x8002u), "");
478    static_assert(helper::canCombine(0x800Fu, 0x8001u, 0u, 1, 0, 0x8001u), "");
479    static_assert(helper::canCombine(0x800Fu, 0x800Fu, 0u, 0, 16, 0x800F0000u), "");
480    static_assert(helper::canCombine(0x800Fu, 0x800Fu, 0x800Fu, 16, 16, 0x800F0000u), "");
481    static_assert(!helper::canCombine(0x1800Fu, 0x800Fu, 0u, 0, 16, 0x800F0000u), "");
482    static_assert(!helper::canCombine(0x1800Fu, 0x800Fu, 0x800Fu, 16, 16, 0x800F0000u), "");
483    static_assert(helper::canCombine(0x800Fu, 0x800F8000u, 0u, 8, 0, 0x800F8000u), "");
484    static_assert(!helper::canCombine(0xFFu, 0x80808080u, 0u, -1, 0, 0x80808080u), "");
485    static_assert(helper::canCombine(0xFFu, 0x80808040u, 0u, 7, 0, 0x80808040u), "");
486    static_assert(helper::canCombine(0xFFu, 0x8000u, 0u, 7, 0, 0x80808040u), "");
487    static_assert(helper::canCombine(0xFFu, 0x101u, 0u, 7, 15, 0x80808040u), "");
488
489    // can combine signed-flagged types only if mask is positive or no shift is required
490    static_assert(!helper::canCombine(0xFF, 0x40808040, 0, 0, 0, 0x40808040), "");
491    static_assert(helper::canCombine(0xFF, 0x40808040, 0, 7, 0, 0x40808040), "");
492    static_assert(!helper::canCombine((i32)0x800000FF, 0x40808040, 0, 0, 0, 0x40808040), "");
493    static_assert(!helper::canCombine((i32)0x800000FF, 0x40808040, 0, 7, 0, 0x40808040), "");
494    static_assert(!helper::canCombine(0x100000FF, 0x40808040, 0, 0, 0, 0x40808040), "");
495    static_assert(!helper::canCombine(0x100000FF, 0x40808040, 0, 7, 0, 0x40808040), "");
496    static_assert(!helper::canCombine(0xFF, (i32)0x80808040, 0, 0, 0, (i32)0x80808040), "");
497    static_assert(helper::canCombine(0xFF, (i32)0x80808040, 0, 7, 0, (i32)0x80808040), "");
498    static_assert(helper::canCombine((i32)0x80007F80, 0x40808040, 0, 0, 0, 0x40808040), "");
499
500    static_assert(helper::canCombine((i32)0x80007F80, (i32)0x80808040, (i32)0x80000000, 0, 0, (i32)0x80808040), "");
501    static_assert(!helper::canCombine((i32)0xC0007F80, (i32)0x80808040, (i32)0xC0000000, 0, 0, (i32)0x80808040), "");
502    static_assert(!helper::canCombine((i32)0x80007F80, (i32)0x80808040, (i32)0x80000000, 1, 0, (i32)0x80808040), "");
503    static_assert(!helper::canCombine((i32)0xC0007F80, (i32)0x80808040, (i32)0xC0000000, 1, 0, (i32)0x80808040), "");
504
505    // can_combine<T, Flag, MASK, [SHARED_MASK], [SHIFT]
506    static_assert(helper::can_combine<i32_0_0, u32, 0u>::value, "");
507    static_assert(helper::can_combine<i32_0_0, u32, 0u, 0u>::value, "");
508    static_assert(helper::can_combine<i32_0_0, u32, 0u, 0u, 4>::value, "");
509    static_assert(!helper::can_combine<i32_0_0, u32, 0u, 1u>::value, "");
510    static_assert(helper::can_combine<i32_0_0, u32, 1u, 0u>::value, "");
511    static_assert(helper::can_combine<i32_0_0, u32, 1u, 0u, 4>::value, "");
512    static_assert(!helper::can_combine<i32_0_0, u32, 1u, 1u>::value, "");
513
514    static_assert(!helper::can_combine<i32_1_0, u32, 0u, 1u>::value, "");
515    static_assert(helper::can_combine<i32_1_0, u32, 0u, 0u>::value, "");
516    static_assert(helper::can_combine<i32_1_0, u32, 0u, 0u, 4>::value, "");
517    static_assert(helper::can_combine<i32_1_0, u32, 1u, 0u>::value, "");
518    static_assert(!helper::can_combine<i32_1_0, u32, 1u, 0u, 0>::value, "");
519    static_assert(helper::can_combine<i32_1_0, u32, 1u, 0u, 1>::value, "");
520    static_assert(helper::can_combine<i32_1_0, u32, 1u, 1u>::value, "");
521    static_assert(helper::can_combine<i32_1_0, u32, 1u, 1u, 0>::value, "");
522    static_assert(!helper::can_combine<i32_1_0, u32, 1u, 1u, 1>::value,
523                  "shouldn't be able to use SHIFT with SHARED_MASK");
524
525    static_assert(helper::can_combine<i32_800f_0, u32, 0x800Fu, 0u, 4>::value, "");
526    static_assert(!helper::can_combine<i32_800f_0, u32, 0x800Fu, 0u, 1>::value, "");
527    static_assert(helper::can_combine<i32_800f_0, u32, 0x800Fu, 0u>::value, "");
528    static_assert(helper::can_combine<Flagged<i32, u32, 0x8002u>, u32, 0x800Fu, 0u>::value, "");
529    static_assert(helper::can_combine<Flagged<i32, u32, 0x8001u>, u32, 0x800Fu, 0u>::value, "");
530    static_assert(helper::can_combine<Flagged<i32, u32, 0x800F0000u>, u32, 0x800Fu, 0u>::value, "");
531    static_assert(helper::can_combine<Flagged<i32, u32, 0x800F8000u>, u32, 0x800Fu, 0u>::value, "");
532    static_assert(!helper::can_combine<Flagged<i32, u32, 0x80808080u>, u32, 0xFFu, 0u>::value, "");
533    static_assert(helper::can_combine<Flagged<i32, u32, 0x80808040u>, u32, 0xFFu, 0u>::value, "");
534
535    // can combine signed-flagged types only if mask is positive or no shift is required
536    static_assert(helper::can_combine<Flagged<i32, i32, 0x40808040>, i32, 0xFF, 0>::value, "");
537    static_assert(!helper::can_combine<Flagged<i32, i32, 0x40808040>,
538                                       i32, (i32)0x800000FF, 0>::value, "");
539    static_assert(!helper::can_combine<Flagged<i32, i32, 0x40808040>,
540                                       i32, 0x100000FF, 0>::value, "");
541    static_assert(helper::can_combine<Flagged<i32, i32, (i32)0x80808040>, i32, 0xFF, 0>::value, "");
542    static_assert(helper::can_combine<Flagged<i32, i32, 0x40808040>,
543                                      i32, (i32)0x80007F80, 0>::value, "");
544
545    static_assert(helper::can_combine<Flagged<i32, i32, (i32)0x80808040>,
546                                      i32, (i32)0x80007F80, (i32)0x80000000>::value, "");
547    static_assert(!helper::can_combine<Flagged<i32, i32, (i32)0xC0808040>,
548                                       i32, (i32)0x80007F80, (i32)0xC0000000>::value, "");
549
550    static_assert(helper::min_shift<Flagged<i32, FLAG, (FLAG)0x80808040>,
551                                    FLAG, (FLAG)0x80007F80, (FLAG)0x80000000>::value == 0, "");
552    static_assert(helper::can_combine<Flagged<i32, FLAG, (FLAG)0x80808040>,
553                                      FLAG, (FLAG)0x80007F80, (FLAG)0x80000000>::value, "");
554
555    // cannot combine non-tagged types
556    static_assert(!helper::can_combine<i32, u32, 0u, 0u>::value, "");
557    static_assert(!helper::can_combine<u32, u32, 0u, 0u>::value, "");
558    static_assert(!helper::can_combine<i32, u32, 0u, 0u>::value, "");
559    static_assert(!helper::can_combine<i32, u32, 0u, 1u>::value, "");
560    static_assert(!helper::can_combine<i32, u32, 1u, 0u>::value, "");
561    static_assert(!helper::can_combine<i32, u32, 1u, 1u>::value, "");
562
563    typedef Flagged<i32_800f_0, u32, 0x800F /* mask */, 0 /* shared mask */> i32_800f_800f;
564    static_assert(i32_800f_800f::sFlagMask == 0x800F, "");
565    static_assert(i32_800f_800f::sFlagShift == 4, "");
566    static_assert(i32_800f_800f::sEffectiveMask == 0x880FF, "");
567    static_assert(!i32_800f_0::sFlagCombined, "");
568    static_assert(!i32_800f_4::sFlagCombined, "");
569
570    static_assert(i32_800f_800f::sFlagCombined, "");
571    static_assert_equals(sizeof(i32_800f_800f), sizeof(i32_800f_0), "");
572
573    typedef Flagged<i32_800f_0, u32, 0x1FFFF /* mask */> i32_800f_1ffff;
574    static_assert(i32_800f_1ffff::sFlagMask == 0x1FFFF, "");
575    static_assert(i32_800f_1ffff::sFlagShift == 0, "");
576    static_assert(i32_800f_1ffff::sEffectiveMask == 0x1FFFF, "");
577    static_assert(!i32_800f_1ffff::sFlagCombined, "");
578
579    // operational tests
580    i32_800f_800f val(0x8000, 0x1234, 56);
581    EXPECT_EQ(val.get().get(), 56);
582    EXPECT_EQ(val.flags(), 0x8000u);
583    EXPECT_EQ(val.get().flags(), 0x1234u & 0x800F);
584    val.setFlags(0x12345);
585    EXPECT_EQ(val.flags(), 0x12345u & 0x800F);
586    EXPECT_EQ(val.get().flags(), 0x1234u & 0x800F);
587    val.get().setFlags(0x54321);
588    EXPECT_EQ(val.flags(), 0x12345u & 0x800F);
589    EXPECT_EQ(val.get().flags(), 0x54321u & 0x800F);
590    EXPECT_EQ(val.get().get(), 56);
591
592    typedef Flagged<i32_800f_4, u32, 0x800F /* mask */, 0 /* shared mask */> i32_800f_800f_B;
593    static_assert(i32_800f_800f_B::sFlagMask == 0x800F, "");
594    static_assert(i32_800f_800f_B::sFlagShift == 0, "");
595    static_assert(i32_800f_800f_B::sEffectiveMask == 0x880FF, "");
596
597    i32_800f_800f_B valB(0x8000, 0x1234, -987);
598    EXPECT_EQ(valB.get().get(), -987);
599    EXPECT_EQ(valB.flags(), 0x8000u);
600    EXPECT_EQ(valB.get().flags(), 0x1234u & 0x800F);
601    valB.setFlags(0x12345);
602    EXPECT_EQ(valB.flags(), 0x12345u & 0x800F);
603    EXPECT_EQ(valB.get().flags(), 0x1234u & 0x800F);
604    valB.get().setFlags(0x5C321);
605    EXPECT_EQ(valB.flags(), 0x12345u & 0x800F);
606    EXPECT_EQ(valB.get().flags(), 0x5C321u & 0x800F);
607    EXPECT_EQ(valB.get().get(), -987);
608
609    typedef Flagged<Flagged<i32, u32, 0xFF>, u32, 0xFF0, 0xF0> i32_ff_ff0;
610    i32_ff_ff0 valC(0xABCD, 0x1234, 101);
611    EXPECT_EQ(valC.get().get(), 101);
612    EXPECT_EQ(valC.flags(), 0xBC0u);
613    EXPECT_EQ(valC.get().flags(), 0xC4u);
614    valC.setFlags(0x12345);
615    EXPECT_EQ(valC.flags(), 0x340u);
616    EXPECT_EQ(valC.get().flags(), 0x44u);
617    valC.get().setFlags(0x54321);
618    EXPECT_EQ(valC.flags(), 0x320u);
619    EXPECT_EQ(valC.get().flags(), 0x21u);
620    EXPECT_EQ(valC.get().get(), 101);
621
622    // when combining flags (with no shift), it should work with signed flags
623    typedef Flagged<Flagged<i32, FLAG, kMask0>, FLAG, kMask1, kMaskCommon> i32_F_ff_ff0;
624    static_assert(i32_F_ff_ff0::sFlagCombined, "flags should be combined");
625
626    i32_F_ff_ff0 valD(kFlag1_A, kFlag0_A, 1023);
627    EXPECT_EQ(valD.get().get(), 1023);
628    EXPECT_EQ(valD.flags(), kFlag1_A);
629    EXPECT_EQ(valD.get().flags(), kFlag0_A);
630    valD.setFlags(kFlag1_B);
631    EXPECT_EQ(valD.flags(), kFlag1_B);
632    EXPECT_EQ(valD.get().flags(), FLAG(0x0BA));
633    valD.get().setFlags(kFlag0_C);
634    EXPECT_EQ(valD.flags(), FLAG(0xBC0));
635    EXPECT_EQ(valD.get().flags(), kFlag0_C);
636    EXPECT_EQ(valD.get().get(), 1023);
637}
638
639} // namespace android
640