Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit c2faf2a

Browse files
authored
[Impeller] Add utility for type safe masks. (#51361)
We use and recommend type safe enums. But when it comes to masks of those enums (`TextureUsageMask`, `ColorWriteMask`, etc.), these are all untyped and you can create one either from a scalar of the enums underlying type, or using ugly and error prone static casts. At the callee, there is no type checking and another error prone static cast. This patch adds a type-safe mask type. This should allow for the migration of something like: ```c++ using TextureUsageMask = uint64_t; ``` with ```c++ using TextureUsageMask = Mask<TextureUsage>; ``` Subsequently, all static casts can be removed with full type checking throughout. This doesn't migrate existing uses yet. That will come in a separate patch.
1 parent f1db33f commit c2faf2a

File tree

4 files changed

+392
-0
lines changed

4 files changed

+392
-0
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39503,6 +39503,7 @@ ORIGIN: ../../../flutter/impeller/base/backend_cast.h + ../../../flutter/LICENSE
3950339503
ORIGIN: ../../../flutter/impeller/base/comparable.cc + ../../../flutter/LICENSE
3950439504
ORIGIN: ../../../flutter/impeller/base/comparable.h + ../../../flutter/LICENSE
3950539505
ORIGIN: ../../../flutter/impeller/base/config.h + ../../../flutter/LICENSE
39506+
ORIGIN: ../../../flutter/impeller/base/mask.h + ../../../flutter/LICENSE
3950639507
ORIGIN: ../../../flutter/impeller/base/promise.cc + ../../../flutter/LICENSE
3950739508
ORIGIN: ../../../flutter/impeller/base/promise.h + ../../../flutter/LICENSE
3950839509
ORIGIN: ../../../flutter/impeller/base/strings.cc + ../../../flutter/LICENSE
@@ -42354,6 +42355,7 @@ FILE: ../../../flutter/impeller/base/backend_cast.h
4235442355
FILE: ../../../flutter/impeller/base/comparable.cc
4235542356
FILE: ../../../flutter/impeller/base/comparable.h
4235642357
FILE: ../../../flutter/impeller/base/config.h
42358+
FILE: ../../../flutter/impeller/base/mask.h
4235742359
FILE: ../../../flutter/impeller/base/promise.cc
4235842360
FILE: ../../../flutter/impeller/base/promise.h
4235942361
FILE: ../../../flutter/impeller/base/strings.cc

impeller/base/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ impeller_component("base") {
1212
"comparable.cc",
1313
"comparable.h",
1414
"config.h",
15+
"mask.h",
1516
"promise.cc",
1617
"promise.h",
1718
"strings.cc",

impeller/base/base_unittests.cc

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// found in the LICENSE file.
44

55
#include "flutter/testing/testing.h"
6+
#include "impeller/base/mask.h"
67
#include "impeller/base/promise.h"
78
#include "impeller/base/strings.h"
89
#include "impeller/base/thread.h"
@@ -250,5 +251,198 @@ TEST(BaseTest, NoExceptionPromiseEmpty) {
250251
wrapper.reset();
251252
}
252253

254+
enum class MyMaskBits : uint32_t {
255+
kFoo = 0,
256+
kBar = 1 << 0,
257+
kBaz = 1 << 1,
258+
kBang = 1 << 2,
259+
};
260+
261+
using MyMask = Mask<MyMaskBits>;
262+
263+
TEST(BaseTest, CanUseTypedMasks) {
264+
{
265+
MyMask mask;
266+
ASSERT_EQ(static_cast<uint32_t>(mask), 0u);
267+
ASSERT_FALSE(mask);
268+
}
269+
270+
{
271+
MyMask mask(MyMaskBits::kBar);
272+
ASSERT_EQ(static_cast<uint32_t>(mask), 1u);
273+
ASSERT_TRUE(mask);
274+
}
275+
276+
{
277+
MyMask mask2(MyMaskBits::kBar);
278+
MyMask mask(mask2);
279+
ASSERT_EQ(static_cast<uint32_t>(mask), 1u);
280+
ASSERT_TRUE(mask);
281+
}
282+
283+
{
284+
MyMask mask2(MyMaskBits::kBar);
285+
MyMask mask(std::move(mask2)); // NOLINT
286+
ASSERT_EQ(static_cast<uint32_t>(mask), 1u);
287+
ASSERT_TRUE(mask);
288+
}
289+
290+
ASSERT_LT(MyMaskBits::kBar, MyMaskBits::kBaz);
291+
ASSERT_LE(MyMaskBits::kBar, MyMaskBits::kBaz);
292+
ASSERT_GT(MyMaskBits::kBaz, MyMaskBits::kBar);
293+
ASSERT_GE(MyMaskBits::kBaz, MyMaskBits::kBar);
294+
ASSERT_EQ(MyMaskBits::kBaz, MyMaskBits::kBaz);
295+
ASSERT_NE(MyMaskBits::kBaz, MyMaskBits::kBang);
296+
297+
{
298+
MyMask m1(MyMaskBits::kBar);
299+
MyMask m2(MyMaskBits::kBaz);
300+
ASSERT_EQ(static_cast<uint32_t>(m1 & m2), 0u);
301+
ASSERT_FALSE(m1 & m2);
302+
}
303+
304+
{
305+
MyMask m1(MyMaskBits::kBar);
306+
MyMask m2(MyMaskBits::kBaz);
307+
ASSERT_EQ(static_cast<uint32_t>(m1 | m2), ((1u << 0u) | (1u << 1u)));
308+
ASSERT_TRUE(m1 | m2);
309+
}
310+
311+
{
312+
MyMask m1(MyMaskBits::kBar);
313+
MyMask m2(MyMaskBits::kBaz);
314+
ASSERT_EQ(static_cast<uint32_t>(m1 ^ m2), ((1u << 0u) ^ (1u << 1u)));
315+
ASSERT_TRUE(m1 ^ m2);
316+
}
317+
318+
{
319+
MyMask m1(MyMaskBits::kBar);
320+
ASSERT_EQ(static_cast<uint32_t>(~m1), (~(1u << 0u)));
321+
ASSERT_TRUE(m1);
322+
}
323+
324+
{
325+
MyMask m1 = MyMaskBits::kBar;
326+
MyMask m2 = MyMaskBits::kBaz;
327+
m2 = m1;
328+
ASSERT_EQ(m2, MyMaskBits::kBar);
329+
}
330+
331+
{
332+
MyMask m = MyMaskBits::kBar | MyMaskBits::kBaz;
333+
ASSERT_TRUE(m);
334+
}
335+
336+
{
337+
MyMask m = MyMaskBits::kBar & MyMaskBits::kBaz;
338+
ASSERT_FALSE(m);
339+
}
340+
341+
{
342+
MyMask m = MyMaskBits::kBar ^ MyMaskBits::kBaz;
343+
ASSERT_TRUE(m);
344+
}
345+
346+
{
347+
MyMask m = ~MyMaskBits::kBar;
348+
ASSERT_TRUE(m);
349+
}
350+
351+
{
352+
MyMask m1 = MyMaskBits::kBar;
353+
MyMask m2 = MyMaskBits::kBaz;
354+
m2 |= m1;
355+
ASSERT_EQ(m1, MyMaskBits::kBar);
356+
MyMask pred = MyMaskBits::kBar | MyMaskBits::kBaz;
357+
ASSERT_EQ(m2, pred);
358+
}
359+
360+
{
361+
MyMask m1 = MyMaskBits::kBar;
362+
MyMask m2 = MyMaskBits::kBaz;
363+
m2 &= m1;
364+
ASSERT_EQ(m1, MyMaskBits::kBar);
365+
MyMask pred = MyMaskBits::kBar & MyMaskBits::kBaz;
366+
ASSERT_EQ(m2, pred);
367+
}
368+
369+
{
370+
MyMask m1 = MyMaskBits::kBar;
371+
MyMask m2 = MyMaskBits::kBaz;
372+
m2 ^= m1;
373+
ASSERT_EQ(m1, MyMaskBits::kBar);
374+
MyMask pred = MyMaskBits::kBar ^ MyMaskBits::kBaz;
375+
ASSERT_EQ(m2, pred);
376+
}
377+
378+
{
379+
MyMask x = MyMaskBits::kBar;
380+
MyMask m = x | MyMaskBits::kBaz;
381+
ASSERT_TRUE(m);
382+
}
383+
384+
{
385+
MyMask x = MyMaskBits::kBar;
386+
MyMask m = MyMaskBits::kBaz | x;
387+
ASSERT_TRUE(m);
388+
}
389+
390+
{
391+
MyMask x = MyMaskBits::kBar;
392+
MyMask m = x & MyMaskBits::kBaz;
393+
ASSERT_FALSE(m);
394+
}
395+
396+
{
397+
MyMask x = MyMaskBits::kBar;
398+
MyMask m = MyMaskBits::kBaz & x;
399+
ASSERT_FALSE(m);
400+
}
401+
402+
{
403+
MyMask x = MyMaskBits::kBar;
404+
MyMask m = x ^ MyMaskBits::kBaz;
405+
ASSERT_TRUE(m);
406+
}
407+
408+
{
409+
MyMask x = MyMaskBits::kBar;
410+
MyMask m = MyMaskBits::kBaz ^ x;
411+
ASSERT_TRUE(m);
412+
}
413+
414+
{
415+
MyMask x = MyMaskBits::kBar;
416+
MyMask m = ~x;
417+
ASSERT_TRUE(m);
418+
}
419+
420+
{
421+
MyMaskBits x = MyMaskBits::kBar;
422+
MyMask m = MyMaskBits::kBaz;
423+
ASSERT_TRUE(x < m);
424+
ASSERT_TRUE(x <= m);
425+
}
426+
427+
{
428+
MyMaskBits x = MyMaskBits::kBar;
429+
MyMask m = MyMaskBits::kBaz;
430+
ASSERT_FALSE(x == m);
431+
}
432+
433+
{
434+
MyMaskBits x = MyMaskBits::kBar;
435+
MyMask m = MyMaskBits::kBaz;
436+
ASSERT_TRUE(x != m);
437+
}
438+
439+
{
440+
MyMaskBits x = MyMaskBits::kBar;
441+
MyMask m = MyMaskBits::kBaz;
442+
ASSERT_FALSE(x > m);
443+
ASSERT_FALSE(x >= m);
444+
}
445+
}
446+
253447
} // namespace testing
254448
} // namespace impeller

0 commit comments

Comments
 (0)